实践中的正式程序验证


65

作为软件工程师,我为工业产品编写了大量代码。相对复杂的东西,包括类,线程,一些设计工作,但也有一些性能折衷的地方。我做了很多测试,对测试感到厌倦,所以我对正式证明工具(例如Coq,Isabelle)产生了兴趣……我可以使用其中之一来正式证明我的代码没有错误并且可以完成吗用它?-但是,每当我检查其中一种工具时,我都不敢相信它们可用于日常软件工程。现在,那只能是我,而我正在寻找有关的指针/观点/想法:-)

具体来说,我的印象是,要使这些工具之一对我有用,就需要大量投资才能向证明者正确定义所考虑程序的对象,方法...。然后我想知道,鉴于证明者必须处理的所有事情,证明者是否会不仅仅耗尽精力。或者,也许我将不得不摆脱副作用(那些证明工具似乎对声明性语言确实非常有用),我想知道这是否会导致无法使用“经过验证的代码”,因为它不会很快,或者足够小。另外,我不能奢侈地更改使用的语言,它必须是Java或C ++:我不能告诉老板我从现在开始要使用OXXXml进行编码,因为它是OXXXml中唯一的语言。我可以证明代码的正确性...

拥有更多形式验证工具经验的人可以发表评论吗?再说一遍-我很喜欢使用正式的证明工具,我认为它们很棒,但是我给人的印象是它们位于象牙塔中,而Java / C ++的低谷使我无法达到……(PS:I也喜欢 Haskell,OCaml ...不要误解:我是声明性语言和形式证明的粉丝,我只是想看看我如何切实地将其用于软件工程)

更新:由于涉及的范围很广,让我们尝试以下更具体的问题:1)是否有使用证明来证明工业Java / C ++程序正确性的示例?2)Coq是否适合该任务?3)如果适合使用Coq,我应该先用Coq编写程序,然后再从Coq生成C ++ / Java吗?4)这种方法可以处理线程和性能优化吗?


3
我得到并感谢您的问题,但是我不明白这个问题的含义(作为SE帖子)。讨论吗?经验?两者都不适合SE。“我该怎么办?” 语气也使我感到这是一个太宽泛的问题。
拉斐尔

3
我明白了。我同意这个问题并未明确提出。因此,让我们说:1)是否有使用证明来证明工业Java / C ++程序正确性的示例?2)Coq是否适合该任务?3)如果Coq适合,我应该先用Coq编写程序,然后让Coq从中生成C ++ / Java吗?4)这种方法可以应对线程和性能优化吗?
Frank

2
那就是四个问题。1)在软件工程方面可能会更好,因为您不太可能在这里遇到(许多)行业专业人员。2)口味有些主观,但是我们这里的人可能会提供客观的观点。据我所知3)是完全主观的。4)对于这个网站是一个很好的问题。总结:请分开您的问题,首先回答软件工程,然后仔细考虑是否可以期望在这里发表目标(!)(!),然后发布2)。
拉斐尔

10
您正在描述正式验证的梦想,但我们离实现目标还有很长的路要走。AFAIK,程序验证是一项非常规任务,仅适用于非常简单的程序。就是说,我认为这个问题是现场的问题,我很感激该地区的某人承认其领域的局限性,解释了最新技术和局限性(也许通过链接一些调查)。
Yuval Filmus

9
验证C ++程序的麻烦在于C ++不是一种定义明确的语言。我认为,直到重新设计软件系统的许多部分(操作系统,库,编程语言)以支持验证,才可能进行大规模验证。众所周知,您不能只在某人上转储200000行代码并说“验证!”。您需要一起验证和编写代码,并且需要使自己的编程习惯适应正在验证的事实。
Andrej Bauer

Answers:


35

对于您的某些问题,我将尝试给出简洁的答案。请记住,严格来说,这不是我的研究领域,因此我的某些信息可能已过时/不正确。

  1. 有许多专门设计用来正式证明Java和C ++属性的工具。

    但是,我需要在这里做个题外话:证明程序的正确性意味着什么?Java类型检查器证明了Java程序的形式属性,即某些错误(如添加a float和an int)永远不会发生!我想象您对更强大的属性感兴趣,即您的程序永远不会进入不想要的状态,或者某个函数的输出符合某个数学规范。简而言之,从简单的安全性到完整的证明程序满足详细规范的证明,“证明程序正确”的含义范围很广。

    现在,我假设您对证明程序的强大特性感兴趣。如果您对安全属性感兴趣(您的程序无法达到某个状态),那么通常看来,最好的方法是模型检查。但是,如果您希望完全指定Java程序的行为,则最好的选择是对该语言使用规范语言,例如JML。有这样的语言用于指定C程序的行为,例如ACSL,但是我不了解C ++。

  2. 有了规格后,您需要证明程序符合该规格。

    为此,您需要一个对规范和语言(Java或C ++)的操作语义都具有正式理解的工具,以便表达适当性定理,即程序的执行符合规范。

    该工具还应允许您制定或生成该定理的证明。现在,这两个任务(指定和验证)都非常困难,因此通常将它们分为两部分:

    • 一种解析代码,规范并生成足够性定理的工具。如Frank 所言Krakatoa就是这种工具的一个例子。

    • 一种自动或交互地证明定理的工具。Coq以这种方式与Krakatoa进行交互,并且还可以使用一些强大的自动化工具,例如Z3

    一个(次要)要点:有些定理太难了,无法用自动化方法来证明,并且已知自动定理证明者有时会遇到健全性错误,从而使它们不那么值得信赖。这是Coq在比较中表现出色的领域(但这不是自动的!)。

  3. 如果要生成Ocaml代码,则一定要先用Coq(Gallina)编写,然后再提取代码。但是,即使有可能,Coq在生成C ++或Java方面也很糟糕。

  4. 以上工具可以处理线程和性能问题吗?可能不是,性能和线程问题最好由专门设计的工具处理,因为它们是特别困难的问题。尽管Martin Hofmann的PolyNI项目似乎很有趣,但我不确定我是否可以推荐任何工具。

结束语:对“现实世界” Java和C ++程序的形式验证是一个庞大而发达的领域,Coq适合完成该任务的一部分。例如,您可以在此处找到高级概述。


感谢这篇文章和您添加的参考。恕我直言,软件工程师的目标是能够快速发布能够1)始终提供正确结果,2)永不失败的系统。我在这里看到一个回归问题,您可能想证明该规范本身是“无错误的” :-)有点像试图用一种元语言定义“一种语言的真正命题”,然后需要另一个元-语言,然后是另一种...
弗兰克(Frank)

6
问题在于用户“想要”的内容通常没有以正式语言表达!对于这个问题,通常没有正式的答案:“这个正式说明符合我的非正式想法吗?”。可以测试一个正式的规范,并证明它具有某些数学特性,但是最终您需要将数学与真实世界联系起来,这是一个非正式的过程。
2013年

是的,当然可以-我一直意识到形式方法只能从定义明确的角度开始。如果该规范是否符合现实用户的有意识/无意识/未发现的需求,则是另一个问题,无法用正式方法解决(但对工程师来说肯定是一个问题)。
Frank

根据定义,一个定理是一个证明的命题。因此,您可能并不是要“证明定理”。
nbro

@nbro维基百科似乎与您同意。但是,Mathworld将一个定理定义为“ 可以通过接受的数学运算证明是正确的”的命题。在这种情况下,不仅可以给出定理证明,而且有必要证明它们成立!:)(这是一个counterquibble,当然)
科迪

15

我想提到形式方法/形式验证工具在工业或非平凡的真实系统中的三种卓越应用。请注意,我在这个主题上经验不足,只能从阅读论文中学习。

  1. NASA在2005年发布的开源工具Java Pathfinder(简称JPF)是一种用于验证可执行Java字节码程序的系统(请参阅Java Pathfinder @ wiki)。它已被用来检测NASA Ames的K9 Rover执行软件中的不一致情况。

  2. 本文:使用模型检查发现严重的文件系统错误@ OSDI'04显示了如何使用模型检查发现文件系统中的严重错误。一个名为FiSC的系统应用于三个经过广泛测试的文件系统:ext3,JFS和ReiserFS,发现了32个严重的错误。它获得了最佳论文奖。

  3. 本文:Amazon Web Services如何使用正式方法@ CACM'15描述了AWS如何将正式方法应用于其产品,如S3,DynamoDB,EBS和内部分布式锁管理器。它着重于Lamport的TLA +工具。顺便说一句,Lamport大量使用了自己的TLA工具箱。他经常在TLA中对他(以及合著者)在论文附录中提出的算法/定理进行(相当完整的)形式验证。


4

程序的正式规范是(或多或少)用另一种编程语言编写的程序。结果,该规范肯定会包含其自身的错误。

形式验证的优点在于,由于程序和规范是两个单独的实现,因此它们的错误会有所不同。但并非总是如此:错误的一种常见来源(被忽略的情况)通常会匹配。因此,形式验证不是万能药:它仍然可能会遗漏大量错误。

形式验证的一个缺点是,它可能会带来两倍的实施成本,甚至可能更多(您需要形式规范的专家,并且需要使用所附带的或多或少的实验性工具;这并不便宜) )。

我猜想设置测试用例并自动运行它们会更好地利用您的时间。


形式验证的优点是……形式验证的第二个缺点是……这令人困惑。
hengxin

我认为规范和非正式任务之间的不匹配是软件需求分析问题,而不是编程问题。
卡夫

3

对于编写为安全关键型嵌入式系统设计的C ++子集的程序,现在可以进行正式验证。见http://eschertech.com/papers/CanCPlusPlusBeMadeAsSafeAsSpark.ppt一个简短的介绍,并http://eschertech.com/papers/CanCPlusPlusBeMadeAsSafeAsSpark.pdf为全文。


5
感谢您的链接。至少对它们的内容进行简短的概述是有用的,以防止链接腐烂,特别是因为您的链接是指向公司网站的:这些链接会定期进行重组,从而杀死了进入该网站的所有链接。
David Richerby,2014年

2

您问几个不同的问题。我同意,用于工业/商业应用的正式验证方法似乎并不普遍。但是,应该意识到,编译器内置了许多“形式验证”原理来确定程序的正确性!因此,以某种方式,如果您使用现代的编译器,那么您将在形式验证中使用许多最新技术。

您说“我厌倦了测试”,但是正式验证并不能真正替代测试。在某种程度上,它是测试的变体

您提到Java。在Java验证程序FindBugs中内置了许多高级形式验证方法,这些方法确实可以在大型代码库上运行。请注意,这将同时出现“假阳性和假阴性”,并且结果需要由开发人员进行审查/分析。但是请注意,即使没有出现实际的功能缺陷,通常也会出现“反模式”,而无论如何在代码中都应避免这种情况。

除了“工业”之外,您无需再提及您的特定应用程序。实际上,形式验证往往取决于特定的应用程序。

形式验证技术似乎已在EE中广泛用于证明电路的正确性,例如在微处理器设计中。

这是Lars Philipson在EE领域对形式验证工具进行调查的示例。


2
说“在编译器中内置了许多“形式验证”原则来确定程序的正确性”是一种误导。您所指的是某些编译器执行的静态类型检查,但是通过这种方式验证的属性非常简单,例如,避免添加数字和字符串。这是有帮助的,但是与“形式验证”通常所理解的却相去甚远。
2013年

2
尽管这是一个简单/常见的示例,但并未具体涉及静态类型检查。imho编译器优化技术广泛且先进,与形式验证原理大致相似,因为它们涉及确定/显示优化程序变体等效性的先进技术。因此,避免在这里出现“移动的目标杆”问题似乎很重要,不要仅仅因为编译器将其完成或将其内置于编译器中,而应该假设其不是形式验证。
vzn

2
同意这不是共识。优化技术大致是创建程序行为的模型,例如循环或子例程,然后对该模型进行优化,然后生成可证明等效的新代码。因此,其中一些优化在重新安排代码方面相当复杂,对我而言,它们利用了形式验证规则。似乎在编译器中还有许多其他形式验证方法的示例...最初的问题问了许多人已经注意到的许多不同问题,是不尝试回答其中包含的所有问题。
vzn 2013年

2
顺便说一句,似乎在JRE,java运行时引擎中也使用了一些正式的验证原理,例如动态优化等
vzn 2013年

3
这就是上面电影中提到的“形式验证的梦想 ”,是一种嵌合的抽象,而务实/功利主义/现实主义产业在很大程度上认可了这一点。数十年来,大型代码库固有地每 K行代码就有错误/缺陷,而且无论理论/技术如何发展,这都是人类的本性,这永远不会改变。实际上,人为建立的数学定理具有相同的性质,尽管这一点并未得到广泛认可!xy
vzn

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.