MISRA C 建议不要使用 malloc,这是否意味着 calloc 更安全?

MISRA C advises against malloc, does this mean calloc is far more secure?

提问人:Ian Stewart 提问时间:10/7/2023 最后编辑:Ian Stewart 更新时间:10/9/2023 访问量:201

问:

我使用 C 已经有几年了,但直到最近才认真努力理解未定义的行为和 C 内存泄漏等陷阱。这是因为现在我在某些代码中多次使用 calloc。MISRA C 的建议是:避免使用容易失败的函数和构造,例如,malloc 可能会失败。我认为这意味着内存分配可能是一个问题,这是否意味着 calloc 是安全的? 如果不是,这是否可取:


uint32_t *array;
        array = calloc(length, 32);

还是只是装点门面?

谢谢你的任何建议,我真的很想避免不良做法。

C 内存 Malloc Misra

评论

0赞 Some programmer dude 10/7/2023
我不知道“可能失败”背后的原因,因为许多功能“可能失败”。包括。我不认为失败与内存设置有关,而是可能会失败并返回一个空指针,即使在使用或任何其他分配内存的函数时也需要检查该指针。malloccallocmallocmalloccalloc
0赞 Some programmer dude 10/7/2023
在 C 语言中,实际上没有其他合适的方法可以从操作系统动态分配内存。在 C 语言中,您必须在任何类型的复杂程序中使用(或 或特定于操作系统的函数等),通常没有其他方法可以解决它。malloccalloc
0赞 mevets 10/7/2023
因此,MISRA的意图 - 动态内存分配是一件坏事。它勉强承认您可以分配内存来容纳基于配置的数据;但您无法释放它或调整它的大小。MISRA也否认了二的赞美算术,认为它的细微差别对凡人来说太难了。由误用的理性支持的确认偏差在他们的工作中起着重要作用。
0赞 Basile Starynkevitch 10/7/2023
否,因为在实践中,大多数实现都是调用(或等效的内部函数)callocmalloc
0赞 Ted Lyngmo 10/7/2023
除了答案和评论之外,阅读平台特定的建议通常会有所帮助。QNX 对“使用内存”有很好的介绍。如果 QNX 不是您的目标,您可能会找到适合您平台的类似内容。

答:

2赞 camelccc 10/7/2023 #1

任何调用都可能失败。如果没有要分配的内存,malloc 将返回 null。如果不检查此返回值,并为内存不足事件提供适当的处理逻辑,则程序可能会崩溃。通常,您唯一能做的就是向用户提供有关情况的消息。

如果您处于安全关键环境中,软件崩溃可能导致车祸,这是非常糟糕的,因此对于任何涉及汽车实时操作的循环,最好避免动态内存分配,因为潜在的递归。

以 calloc 形式装点门面不会有任何区别。

评论

1赞 John Bollinger 10/7/2023
"任何调用都可能失败“——是和否。MISRA 问题与具有已定义故障模式的函数有关,但并非全部。其中,MISRA关注的是容易失败的功能,这有点模棱两可,但比所有功能都要少得多。
0赞 DevSolar 10/8/2023
"malloc将返回 null“——仅当您的操作系统没有过度使用内存的习惯时。
2赞 Ted Lyngmo 10/7/2023 #2

只是装点门面吗?

确实如此。是否使用 or(与 + 初始化相同)并不重要。malloccallocmalloc

关键是检查返回值。

MISRA:

避免使用容易失败的函数和构造

脱离上下文,这让想要进行动态内存分配的人别无选择,只能

  1. 忽略 MISRA 的建议,只需确保检查每个分配。
  2. 在程序启动时进行较大的静态分配,并将其用作整个程序中唯一的内存池。提供证据,证明您的计划永远不会超过所做的分配。

评论

0赞 Ian Stewart 10/8/2023
“在程序启动时进行大的静态分配”:我正在处理的程序从文件中读取文本。我已经测试了 50,000,000 个字符,但我可能最多只需要 48,000 个字符。一个 100,000 个数组应该很容易就足够了,但是使用 50,000,000 个元素的数组中的 48,000 个元素会不会只会引入另一组问题?
0赞 Ted Lyngmo 10/8/2023
@IanStewart好的。它是否需要始终可用,或者每次都读取文件是否是一种替代方案?
1赞 Ian Stewart 10/8/2023
@TedLyngmo:我认为这就是解决方案,分块读取文件 - 永远不需要一次完整的文本。此外,永远不需要 50,000,000 个字符 - 这只是测试代码的一种方式,因为我在开始时遇到了问题,当时我无法让它读取超过 1047 个字符。我将查看通常需要多少文本并使用静态分配。然后在需要时处理异常 - 可能很少,也许永远不会。
0赞 Lundin 10/8/2023 #3

MISRA C 在谴责 malloc + 朋友时出奇地简短。动态分配是各种安全相关应用中的主要罪过,其他所有相关的标准也都禁止它(IEC61508 + 和其他“SIL”标准(火车、家用电器等)、ISO 26262、DO178、JSF 和 NASA 标准等)。

由内存不足导致的潜在错误可能是该函数问题最少的问题 - 因为如果你的内存不足,这意味着你的整个程序设计被破坏了,这不是 malloc 本身的错。malloc

这篇 Codidact 博文详细回答了您的问题,包括嵌入式系统中 malloc 和动态分配的众多严重问题:
为什么我不应该在嵌入式系统中使用动态内存分配?

至于可以使用什么来代替,与安全相关的应用程序使用静态大小的缓冲区。在某些情况下,内存池也是可以接受的,只要您在那里进行错误检查/处理,请在此处查看我的答案。

评论

0赞 Ted Lyngmo 10/8/2023
没有人问过一个问题,这些很好的信息可以作为答案。
0赞 Lundin 10/8/2023
@TedLyngmo“malloc + friends”的意思是 malloc + calloc + realloc,我认为这是显而易见的。
1赞 Andrew 10/9/2023 #4

MISRA C 的建议是:避免使用容易失败的函数和构造,例如,malloc 可能会失败。我认为这意味着内存分配可能是一个问题,这是否意味着 calloc 是安全的?

MISRA C:2012(并持续到 :2023)非常清楚:

  • 指令 D.4.12 - 不得使用动态内存分配

如果这还不够:

  • 规则21.3 - 不得使用内存分配和解除分配功能<stdlib.h>

在规则 21.3 中,放大甚至列出了以下功能:

  • callocmallocreallocaligned_allocfree

因此,对您的问题的简单回答是:不,如果您希望符合 MISRA C 标准calloc 是不行的。

评论

0赞 Ian Stewart 10/9/2023
感谢您的回复并列出功能 - 非常宝贵,尤其是它们来自主席。从这次宝贵的讨论中,我现在已经从我的代码中删除了所有动态内存分配。良好的实践和安全的代码是我真正想正确学习的东西,这通常是我在这个论坛上提问的原因。
0赞 Ian Stewart 10/9/2023
一个相关的问题;这是否意味着最好完全删除 <stdlib.h> 并在需要uint32_t时使用 <stdint>?当然,除了有时我需要exit()。
0赞 Andrew 10/9/2023
我建议直接使用...虽然 MISRA C 的许多功能都受到限制,但并非所有功能都受到限制 - 因此与其他一些头文件不同,没有完全的限制(尽管其中一些需要审查)<stdint.h><stdlib.h><stdlib.h>