安全编码实践

Safe coding practices

我正在开始一个新的 C/C++ 嵌入式应用程序,并正在尝试自学安全编码实践,例如 MISRA、AUTOSAR 和我目前最喜欢的可能是因为它是最短的,即 NASA 所谓的 Power of 10 (https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety-Critical_Code)。我可以看到许多规则背后的逻辑。但它们都试图消除或限制动态内存分配。例如,MISRA C++ 规则 18-4-1 说:“不得使用动态堆内存分配”,而 NASA 的规则 3 是“避免堆内存分配”。 AUTOSAR 的限制较少。我理解他们的意图是确保系统不会 运行 内存不足,但我不太清楚 C 或 C++ 编译器将什么分配为“动态堆内存分配”或“堆内存分配”。我将编辑此 post 以提出具体问题

  1. 这是否意味着所有变量都必须是静态的? (@klutt
  2. 已回答
  3. 为了确保我理解正确,在堆栈上声明的方法内部定义的临时变量是否因此根据 MISRA、AUTOSAR 和 NASA 准则“安全”?
  4. 根据AUTOSAR和NASA指南初始化后“new”不能使用?
  5. C++ 库数组是否符合 MISRA、AUTOSAR 和 NASA 指南?
  6. 但是根据 AUTOSAR 和 NASA 指南,不能使用像 string 和 vector 这样的 C++ 库?
  7. 根据指南的“不安全”动态内存分配的任何其他示例 将不胜感激

谢谢 - 吉恩

MISRA 规则的核心是动态内存分配问题

  1. 程序员天生懒惰,不检查 malloc() 的 return 状态导致使用空指针。
  2. 堆碎片的一般问题
  3. 不完整 malloc() 及其兄弟姐妹的标准定义,充满了未定义、未指定和实现定义的行为,这使得编译器和实现之间具有可移植性,并且因此,行为具有一定程度的不可预测性。

MISRA C/C++ 的一些衍生产品(例如 JSF、NASA JPL、AUTOSAR)允许在初始化阶段使用 malloc()(但不允许 realloc() 等或后续 free()) 它消除了所有的碎片问题——但没有解决不完整的定义。

当然,自定义解决方案可能是完全可证明的,在这种情况下,偏差 MISRA 规则就可以了。

但总的来说,使用动态内存的缺陷大于任何潜在的好处。

免责声明:是的,我与 MISRA 有关联...查看个人资料

Does that mean for example that all variables need to be static?

不,它们也可以是本地范围(自动存储)。如果在文件范围内声明,它们通常应该是 static(受到 MISRA-C 和其他人的鼓励)。

Just to make sure I understand correctly, are temporary variables defined inside methods declared on the stack and therefore "safe" according to the MISRA, AUTOSAR and NASA guidelines?

是的。虽然你需要考虑堆栈溢出,但那是另一回事了。

"new” can’t be used after initialization according to the AUTOSAR and NASA guidelines?

是的。

The C++ library array is OK according to the MISRA, AUTOSAR and NASA guidelines?

完全没有,您可以使用标准库的哪些部分会有限制,特别是在 MISRA-C++ 中。 MISRA 指南中有一章说明了 headers 不应使用的规则。不过这些都相当宽松,只禁止最疯狂的东西,比如 setjmp.h 和其他托管系统的东西,比如 signal.h.

对于更高级别的 safety-critical 系统,如果可能,您最终将要求标准库本身也遵循 MISRA。这种情况很少见,所以大多数情况下您会尽量避免使用标准库。

But C++ libraries like string and vector can’t be used according to the AUTOSAR and NASA guidelines?

不,他们不能。 C++ 库通常不适用于嵌入式系统。就我个人而言,我绝不会远程使用 C++ safety-critical,而且我在一般嵌入式项目中使用 C++ 的经验非常糟糕。

可以很好地使用它,但它需要 C++ 程序员做很多工作,基本上你需要充分了解哪些部分构成安全子集,哪些部分构成安全子集那不是,每个 C++ 行的汇编结果是什么。普通的 C++ 程序员没有足够的技能来做到这一点,所以如果 C++ 可用,他们很快就会在项目中加入危险或臃肿的功能。

此外,该语言从 C++11 及更高版本开始变得更加混乱,变得越来越不适合具有更多 poorly-defined 行为、更多类型双关规则和指针别名等的嵌入式系统。记录所有poorly-defined C++ 行为案例,你可以写一本厚书。

Any other examples of "unsafe" dynamic memory allocation per the guidelines would be appreciated

主要doesn't make any sense用于嵌入式系统。如果您知道堆在 MCU 中是如何实现的,那么常识就足以看出为什么堆不能满足任何目的。但也因为动态分配假设某种方式的 non-deterministic 行为是好的,这在 safety-related 软件中从来不是这种情况。


关于这些 NASA 规则,它们是相当肤浅和幼稚的。他们中的大多数都是不言而喻的,MISRA-C 远远超过 in-depth。您可以将 NASA 规则视为 beginner-level 东西:迟至 2006 年提出这些规则的人似乎错过了 1990 年代关于开发更安全的 C 子集的所有研究。

这里讨论了 NASA 从未管理过的关于“无函数指针”的愚蠢规则:State Machine with no function pointer