安全关键项目中动态分配的替代方案(C语言)

11

在安全关键项目中,不建议使用任何动态分配或释放已分配的内存。仅在程序执行的详细化/初始化阶段允许使用。

我知道你们大多数人会争论要在软件中实现全部静态分配,或者在代码中进行一些证明,即动态分配不会影响整个程序等,但是,这个问题有没有其他解决方案?是否有任何方法或任何示例来在程序初始化/详细化期间分配一些(堆)内存,并从那里分配/释放内存?如果我们真的需要在(安全关键)项目中使用动态分配,是否有任何解决方案/替代方法?

1个回答

21

这种类型的问题通常由开发人员提出,他们希望能够在安全相关系统中使用动态内存分配而没有"不必要"的限制 - 这往往意味着他们在选择时不会受到阻止以及可能在选择时动态分配任意数量的内存,并在需要时释放该内存。

首先,我将回答这个问题(在有无限制的情况下是否可以在关键系统中使用动态内存分配?)。然后,我将回到接受某些限制以控制动态内存分配如何使用的选项。

在“安全关键项目”中,这种事情通常是不可能的。安全相关系统通常具有弥补或消除指定危险的强制要求。未能充分减轻或消除指定危险(即未能满足要求)可能会导致伤害 - 例如,人员死亡或受伤。在这种系统中,通常需要确定某些级别的严格程度,以确保适当可靠地减轻或消除危险。这样做的一个结果通常是一组与确定性相关的要求 - 通过适当的分析,能够确定系统以指定的方式完成操作的能力,其中行为和时间等属性得到严密的规定。

如果不受限制地使用动态内存分配,很难确定系统的部分是否按照要求运行。可能出现以下问题:

  • 未分配内存的碎片。无法确保分配N个连续字节的内存的请求将成功,即使有N个可用的内存字节也是如此。如果之前有任意顺序的多次分配和释放,尤其是如果N个内存字节可用,则它们可能不在一个连续的区块中。
  • 充足性。往往很难保证必须成功的关键内存分配确实成功。
  • 适当释放。很难防止在仍然需要内存时释放该内存(导致访问已被释放的内存),或者确保不再需要的内存实际上被释放(例如,防止内存泄漏)。
  • 时效性。 试图缓解上述问题意味着分配或释放的时间是可变的、不可预测的,并且可能没有上限。处理这些问题的方法包括碎片整理(处理碎片化问题)或垃圾回收(处理足够性和/或适当释放问题)。这些过程需要时间和其他系统资源。如果在尝试进行分配时进行这些操作,分配内存的时间就变得不可预测。如果在释放内存时进行这些操作,则释放内存的时间也变得不可预测。如果在其他时间进行这些操作,则其他关键代码的行为可能变得不可预测(例如,对于应用程序来说,世界实际上会冻结)。

所有这些因素以及更多因素意味着,在确定系统时间或资源使用的要求方面,无限制的动态内存分配效果不佳。基本上,系统要求需要施加一些限制,并根据系统情况强制执行这些限制。

如果可以接受对动态内存分配的限制,则有多种选择。通常,这些技术需要在政策约束和技术解决方案方面得到支持,以鼓励(最好在高度关键性的系统中强制执行)遵守这些政策。政策执行可能是技术性的(例如,自动和手动的设计和代码审查、定制开发环境、合规测试等等)或组织性的(例如,解雇故意违反关键政策的开发人员)。

技术方法的例子包括:

  • 根本不使用动态分配。 即仅使用静态分配。
  • 只在系统初始化期间使用动态内存分配。 这需要预先确定需要分配的最大内存量。如果分配内存失败,则将其视为任何POST(自检)故障。
  • 分配内存但永远不释放它。 这往往避免了碎片化问题,但可能会使确定系统所需内存的上限更加困难。
  • 自定义分配。系统(或应用程序)显式地管理动态内存分配,而不是使用通用库函数(例如与所选编程语言相关的函数)。这通常意味着引入一个自定义分配器并禁止(或禁用)使用通用库函数进行动态内存管理。自定义分配器必须明确地根据特定系统的需求进行设计。
  • 内存池技术。这是一种特殊类型的自定义分配,其中应用程序分配一块内存池,并从中固定请求一定量的内存(或固定量的倍数)。由于应用程序固定了内存池的大小,因此可以监视内存池中正在使用的内存量,并在内存耗尽时采取释放内存的措施。从内存池分配和释放内存也可以被可预测地执行(因为正在管理一些更一般的动态内存分配问题)。关键系统可能会有多个内存池,每个内存池专供特定功能集合的独占使用。
  • 分区。 明确防止非关键功能访问已为关键功能建立的内存池。这可以确保关键功能能够访问它们需要的内存,并帮助确保低关键性功能的失败不会触发高关键性功能的失败。分区可以在应用程序内部或(适当认证的)主机操作系统内部执行,也可以两者兼而有之……具体取决于系统的需求。
  • 其中一些方法可以相互支持。


    感谢您提供这个好的描述,包括典型问题列表和典型解决方案列表。对于后者,我想再添加一个:实现一种诊断方法,以确定上述错误之一已经发生。最典型的例子可能是在分配之前(或之后)检查分配水印:如果软件耗尽堆内存,则强制系统进入安全状态。 - HelpingHand

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接