例如,当为关键的实时应用程序(例如航空中使用的那些应用程序)创建软件时,您如何确定它会毫无问题地运行?您是100%确定还是90%以上确定?

我们看到每个软件应用程序中都不断添加错误修复程序。修复它,尤其是在关键任务应用程序中?异常处理能走多远?

评论

“如果该错误在有机会修复之前就被重新发现,特别是在关键任务应用中,该怎么办?” -那么您希望应用程序具有安全的故障模式。

我讨厌这个标题,也喜欢下面的这些答案。

因为已经存在的答案很棒,所以不打算添加答案。但是出于好奇,您听说过Therac-25吗?这是具有灾难性后果的软件错误的典型示例。

我曾经读过一份有关Therac 25的说明,最后说到该公司已放弃制造医疗机器,而回到了核反应堆控制器的核心业务。大嘴巴。

即使没有错误,也需要进行异常处理。例如,您想要优雅地处理无法纠正的内存错误:lwn.net/Articles/348886

#1 楼

他们不能100%确定没有错误的系统。通过使用静态分析和测试,他们可以提高对系统没有错误的信心。有些人主张将错误作为一种估计系统中仍有多少错误的方法。静态分析至少有两种形式。

如果系统出现错误,那么它就会出错。有各种各样的方法可以减少故障的影响。拥有检查一致性的代码,然后放弃事务,甚至重新启动流程或整个系统的做法很常见。为确保系统在某些类型的故障后重新启动,通常使用看门狗计时器。

评论


当然,静态分析可能会出错:P实际上,这适用于任何形式的测试和分析-最终,有人编写了软件,有人组装了证明,有人忘记说明了这个平台,其中1 + 1并不并不总是等于2 ...有很多的bug机会。当然,手动测试也不例外。

–罗安
16年3月16日在17:11

是的,它可以是无错误的,请参见我的答案中的维基百科文章(有关“错误”和“免费”的某些定义)。证明系统正确是一项艰巨的工作,越野车系统更便宜。

–Peter M.-代表莫妮卡(Monica)
16-3-16在22:27



@PeterMasiar如果将错误定义为不符合规范,则可以尽力证明没有程序不符合规范的领域。您不能做的就是证明规范本身不包含任何错误。这是认识论的限制,而不是技术上的限制。这种情况的观察至少可以追溯到1953年出版的维特根斯坦(Wittgenstein)的《哲学研究》。

–诺亚·萨斯曼(Noah Sussman)
16-3-17在21:04



@immibis好,谢谢。请在我的答案中看到指向“调试”的链接。另请参阅此页面,建议“重新调试”是贬义术语,用于某些软件开发人员所做的工作,urbandictionary.com / define.php?term = rebugging

– AdrianHHH
16 Mar 18 '16 at 10:15

@immibis,请接受我的歉意。对于Stack Overflow上的许多人来说,英语是一种难懂的语言,而不是他们的母语。我尝试写清楚,并使用适当的词语。您使用了一个看起来合理的单词,我不记得它的定义,所以我查了一下,发现它表达了意想不到的东西。鉴于Urban Dictionary,您希望您的一位同事说:“嘿Immibis,您是否正在调试该程序?”我不希望那句话对我说。

– AdrianHHH
16 Mar 19 '16 at 17:32

#2 楼

NASA位于戈达德的软件保障技术中心曾经进行过一次测试,以查看在航天飞机的某些代码中可以发现多少缺陷。经过真正严格,极其昂贵的过程,并进行了多个级别的审查,使用了非常小的函数来最大程度地降低每一个的风险,他们设法将其减少到每10,000行代码1个缺陷(可能是10万,我忘记)。迄今为止,这是有史以来编写的最无缺陷的代码。

他们的最终决定是,这种软件生产模式对地球上的任何人都没有用处或不可用:不能这样写他们的所有代码,甚至也不写他们所有的关键任务代码,即使在完美主义上花费了大量的金钱和时间,他们也只能设法减少缺陷,而不能消除缺陷。

在实际上,他们再也没有为该标准开发代码,因为这样做根本不经济。

[编辑:我错了。在评论中,@ Benjaminssp提供了一个链接(http://www.fastcompany.com/28121/they-write-right-stuff),表明SATC继续努力实现零缺陷代码,并实现了错误率看起来每个MLoc大约有2个错误-坦白地说,这对我来说很令人难以置信,但是它们表明可以实现!但是,我觉得我的观点仍然存在,尽管已大大削弱:即使是NASA也无法完全摆脱缺陷。开发人员通常会要求其他质量检查人员。您可以说的最好的是:“对于我们测试过的输入,您的代码符合规范,假设我们的测试正确无误,则实现了100%的代码覆盖率。”

始终记住,测试代码本身每千行会有一些缺陷。

评论


+1对于测试,如果您将其检查得较大,也将出现故障。人们只会犯错误:)

– Niels van Reijmersdal
16 Mar 16 '16 at 13:54

您对此有参考吗?

–rdans
16 Mar 16 '16 at 15:27

这是一个消息来源,尽管它并未透露该程序的终止信息:fastcompany.com/28121/they-write-right-stuff

– Benjaminssp
16 Mar 16 '16 at 15:44

@DewiMorgan而且它仍然非常昂贵。处理单个错误可能意味着损失十亿美元设备的事情可能值得,但是哦:)

–罗安
16 Mar 16 '16 at 17:07

@Luaan忘记了10亿美元的设备,在一次极高的宣传事故中,大约有六个人会丧生?

–用户
16 Mar 17 '16 at 12:40

#3 楼

所有不平凡的软件都有错误。风险是生活的一部分。尝试消除所有可能的风险是很困难的,因为在此过程中,您会引入无能为力的风险。真空:它取决于编译器,解释器,库,操作系统以及您几乎无法控制的其他系统。最重要的是,人们需要以规定的方式使用,配置和管理您的软件,而您可能未充分沟通。任何运维人员都会告诉您,系统所依赖的一切都是错误的,不完善的,并且有时甚至是可靠的。我关心的是消除软件中的所有错误。”如果确实如此,那么恭喜您,我希望您从现在起一年后仍能继续经营业务。这些可能性也很可能是您的问题。您的客户/用户不在乎您的系统是否由于算法错误或配置设置通信不佳而损坏。如果您的工作是提高质量,那么最好花时间在这个更大的背景上。相反,您需要管理风险:在某件事情出错的可能性,该件事情将造成的损害以及如何从中恢复之间做出权衡。擅长打造可持续发展的事物的人-包括整个企业-真的要做到这一点。

评论


我知道我们不该评论“我也是!”,但我也要评论! -您说的是“所有非凡的软件都有bug”,这恰恰是我发现自己每周至少开会两次的意思。这是一项重要的口头禅,也是一种方法,可以帮助测试人员将重点放在哪些故障上是重要的,因为这些故障属于标准操作范围。

– Baronz
16 Mar 16 '16 at 15:45

当然,这也指出了减少错误的方法:编写更多琐碎的代码。复杂度越大,错误密度越大。

– Dewi Morgan
16 Mar 16 '16 at 17:05

琐碎的软件最大的缺点是:它不能解决问题。一旦您到达琐碎的软件可以解决某人的问题的地步,它就已经存在了漏洞。至少,有些用户会认为某些行为是错误的(而其他行为则是相反的):P而且甚至不让我着手“环境错误”。即使在用户要运行它的所有环境中,平凡的程序也能正常运行,祝您好运。这些年来,许多美国软件仍然无法在大多数欧洲国家/地区使用。

–罗安
16 Mar 16 '16 at 17:08



这是一个很好的答案。我想补充一点,即使软件完美,它也可以在硬件上运行。存在硬件错误和硬件错误。

–emory
16 Mar 16 '16 at 19:03

#4 楼

软件并非没有缺陷。

在处理关键任务软件时,当然,您需要在质量保证上投入更多的资金,并且您需要拥有最好的开发人员,并且需要获得他们使用所有精美的工具并使用它们(包括为工作选择最佳语言)。尽管如此,您仍然会遇到bug。

主要的解决方案基本上是一种纵深防御。从最广泛的意义上讲,您希望多个独立的系统使用多种单独的方式来获得相同的答案。这样,如果某些路径失败,您会注意到错误,如果幸运的话,您将有一种选择正确答案的方法。从航天飞机到核电站,这不仅在软件中得到广泛应用。

您还需要了解故障模式。可能没有任何长期影响的故障-这是相当轻微的故障。如果存在一个临时问题导致程序“安全”崩溃,那么重新启动可能就足够了。在许多关键任务场景中,这非常好,尤其是与上述冗余结合使用时。如果有可能以无法通过重新启动解决的方式破坏保存的状态,或者如果同一错误可能导致您的系统以不符合任务要求的规模反复失败,那么您将面临更多麻烦。最糟糕的情况是无提示的故障-基本上,出现了问题,但是并没有引起任何警报。这可能导致数据长期损坏,并且在被检测之前会造成相当大的伤害。同样,请参见上面的冗余。不同的故障模式之间存在一些重叠-例如,一旦我们取回数据(光较慢),可能会发现燃烧时间长于预期的探针(但是,到那时它可能已经丢失)。不过,您还是想知道失败的原因,所以无声的失败通常非常难看。

毫不奇怪,关键任务系统对于开发和部署而言往往相当昂贵,并且它们具有许多其他约束并且通常具有有限的速度(例如,您可能有三种不同的算法相互检查,但是其中一种比其他,因此您只需检查一下即可获得更快的结果)。与往常一样,工程是要权衡的。

#5 楼

每个人都在重复说所有不平凡的程序都有错误。这仅说明了软件工程作为一个研究领域还远未成熟,以及计算机科学(以正确的方式解决理论问题)和软件工程(以实用的方式解决实际问题)之间的巨大差距。 br />关于形式化程序验证的研究全是整个过程–整个过程就是证明程序是正确的(没有错误)。

答案是:是的,它们可以被证明是正确的,但是工作量很大。我记得Dijkstra编写了简单的操作系统,并证明它可以根据要求工作,但我找不到链接。 )。由于成本的原因,几乎没有人在商业应用中这样做。处理这些错误要比派生程序(并证明它正确)便宜。

评论


正式的程序验证和证明属性只能验证程序是否符合某些特定的形式要求。这绝不能确保该程序没有错误,因为现实世界中的一大类错误是程序行为与指定要求完全匹配,但是在某些特定情况下,这些要求与实际业务需求不匹配或用户期望-因此,尽管理论上是“正确的”,但系统还是有故障,损坏并且需要修复。本质上,您只需要从担心代码中的错误变成正式要求中的错误即可。

– Peteris
16-3-16在20:17



“当心上面代码中的错误;我只是证明了它是正确的,没有尝试过。” -唐纳德​​·努斯

–马克
16年3月16日在22:22

如果您的要求足够详细,可以派生最终代码,那么这些要求的形式实质上只是一种高级编程语言。对于非平凡的系统,与所产生的代码库相比,任何稍微详细的要求的大小和复杂度都将是巨大的,并且开发它的过程与开发普通代码一样容易出错。

– Peteris
16 Mar 17 '16 at 10:08

一位土木工程师也无法证明自己的桥梁也不会倒下-他所能展示的只是它通过了一系列场景的测试。在没有自己从事软件工作的人们中,常见的失败是未能掌握软件工程就是工程学,并且对其应用相同的标准。是的,有大量关于形式证明的工作-这是象牙塔学者失去真实世界轨迹的经典示例,无法产生一种在实践中不可用的可爱理论。

–格雷厄姆
16 Mar 17 '16 at 10:51

虽然您可以使用形式验证来证明程序符合规范,但是您不能通过任何形式方法来证明规范不包含任何错误。您可以证明符合性,但不能证明正确性。

–诺亚·萨斯曼(Noah Sussman)
16-3-17在21:10



#6 楼

错误免费(Bug Free)是一个松散使用的术语。有人设法对软件进行了自动验证,证明了如果由符合标准的编译器进行编译,则微内核将按照其API文档中的描述运行。

“高可靠性软件”致力于获得几乎没有错误。他们严重依赖诸如


之类的语言功能,将语言功能限制为最容易验证的功能
严格的同行评审过程
严格的测试

>随着可靠性的提高,您可能还会发现特定领域的需求开始指定特定行为,这些行为必须比其他行为更可靠。例如,我见过需要对内存中的随机位翻转具有弹性的软件。结果,在某些特别关键的位置,他们将32位字用作布尔值,并精心构造了两个都不为零的值,以使其具有某些特性,从而更容易检测到位翻转。

最后,超高可靠性软件的局限性在于它所运行的硬件。当您达到此极限时,通过减轻硬件的不可靠性,而不是尝试开发在理想的抽象机上更可靠地工作的软件,可以更好地获得可靠性。

#7 楼

如果您是负责生产安全关键代码的企业,那么您将学习如何:


编写和解释适当的要求(大多数错误是由要求引起的)
按照国际编码标准编写代码
严格测试您的代码;语法,覆盖范围,错误处理,正常降级等许多方面
严格集成您的代码
进行无情重构
进行审核
再次进行测试
遵循正确的做法;计划,版本控制,审查,错误报告...
进行测试

有很多工具可用于所有这些事情。您可以参加很多课程。如果您不知道答案,可以使用顾问。这不是不可能的。当然,您永远不会发现所有的错误,但是可以确保您的软件不会杀死任何人。

以我的经验,安全性至关重要的软件的生产时间是其他产品的两倍。 />

评论


少两次?

– AdrianHHH
16 Mar 17 '16 at 20:12

“当然,您永远找不到所有的错误,但是您可以确保您的软件不会杀死任何人。” -因此您无法向开发人员保证他们的软件没有故障。您怎么知道您的软件不会杀死任何人?

–乔·斯特拉泽(Joe Strazzere)
16 Mar 20 '16在15:46

@Joe Strazzere好吧,如果失败,它将通过一条消息优雅地停止,而不是在该位置随机发射导弹。诸如此类的事情。

– RedSonja
16年3月21日在12:00

@RedSonja-当然,但是,如果您“永远找不到所有的臭虫”,您如何知道这些“未发现”的臭虫之一不会随机发射导弹?我断言您实际上不确定。

–乔·斯特拉泽(Joe Strazzere)
16-3-21在22:22

@Joe Strazzere好吧,我必须测试每一行以及每种可能的输入数据组合。我可以说它满足要求。我已经签署了测试报告,根据德国法律,如果我让一个漏洞通过并且有人死亡,那就是我要入狱。他们进行实际的现场射击测试时,我必须在那里。我尽我所能。要求中可能存在错误-我发现并报告了很多不一致之处。它不会随机发射火箭。如果您得罪了它,它只会无所事事,直到您再次与之友好交谈。

– RedSonja
16-3-22在6:51

#8 楼

我认为没有任何人可以保证自己的软件没有漏洞,而不会欺骗您。

但是,有一种称为形式验证的东西,可以使人获得正确性的证明。在正式验证中将某个软件定义为“正确”时,这意味着该软件符合所设置的规格。请参阅:https://en.wikipedia.org/wiki/Formal_verification


示例:此状态机的规范是它只能从onoff,反之亦然。换句话说,在onoff上都不应有任何循环。对于此示例:初始条件可以是onoff。在这里,您可以在搜索空间中搜索两个开始条件,以验证是否存在可能会破坏您的规范的事件字符串。

#9 楼

没有这样的无故障软件。实际上,有一个...它是您的Hello World程序,但是您知道,没有人使用这样的程序。但是,有一些实践方法可以帮助我们尽可能地预防或发现问题,例如:


代码审查
单元测试
需求分析
测试驱动开发


#10 楼

存在无错程序,但它们也需要bugix。

问题是合乎逻辑的,但它基于错误的假设:“您看到没有无错程序,因为错误修复程序是在不断进行的。任何程序”。实际上,无故障程序仍可能导致问题,并且可能需要修正错误。可以对程序进行100%验证以仅获得预期结果,但是您不能期望在实际环境中获得所有可能的结果,尽管如此,其中某些结果仍然比其他结果更为理想。

示例: 2 + 2 =?

#include <iostream>

void main()
{
    int result;

    result = 2+2;
    std::cout << "The answer is " << result;
}


该程序似乎过于简单,无法被窃听。但是,仍然有两个潜在的问题需要解决。到底是什么



答案

第一个是我们的程序不是标准程序,符合。 ANSI / ISO标准C实际上要求main()返回一个值。这主要是可维护性和兼容性问题。

第二个是功能性问题。在Unix中从命令行启动时,它返回“答案是4”而没有换行符:

问题。如您所见,这与异常处理无关,与预期结果和实际结果之间可能存在的差异有关。

所有错误修正后的代码: />