3

这个问题与遵循 MISRAC:2012 指南的 ISO C99 编码有关。

我正在寻找有关 Dir 4.8 “如果指向结构或联合的指针从未在翻译单元中取消引用,则应隐藏对象的实现”以及 Dir 4.12 “不应使用动态内存分配”的指导。

在 C 中实现抽象数据类型时,通常使用句柄来引用 ADT,句柄是指向描述 ADT 内部状态的结构的指针。这可以使用 Dir 4.8 中的不透明指针来完成,其好处是内部细节对用户保持隐藏。

通常这些 ADT 中可能存在多个,因此必须有一种方法来创建多个句柄。这可以通过在初始化函数中为句柄引用的内部细节分配内存来解决,但是在 Dir 4.12 下这是不允许的。

另一种选择是初始化例程接收指向用户提供的静态分配句柄的指针,但是,这不能使用不透明指针来完成。

我在下面说明问题。

    Module.h 

    struct module; 
    typedef struct module module_t; /* Module handle is only available to  the world as an incomplete type. This allows us to satisfy MISRAC 2012 Dir 4.8.*/

    Module.c

    #include "module.h"
    struct module
    {
        uint8_t value;
    };
    module_t* module_get_a_handle(void)
    {
         return (module_t*)malloc(sizeof(struct module)); /* MISRAC 2012 Dir 4.12 disallows dynamic memory allocation.*/
    }

    User.c

    #include "module.h"
    module_t* module_handle;
    module_handle = module_get_a_handle();

这个问题也描述了这个问题 Static allocation of opaque data types,但是没有针对 MISRAC:2012 指南进行讨论。

所描述的一种解决方案是使用静态分配的句柄池,这些句柄池可供客户端代码使用。这个解决方案似乎在技术上是合规的;但是,这里似乎仍然存在动态内存分配的概念。我认为尽管句柄是静态分配的,但编译器无法在编译期间确定是否有足够的句柄可供软件正常运行。

我对这个问题的解决方案是围绕 Dir 4.8 编写一个偏差,并使用非透明指针和强大的命名约定,让用户清楚地知道 ADT 的内部细节不得更改。

我很好奇是否存在满足 Dir 4.8 和 Dir 4.12 且不违反任何其他 MISRAC:2012 规则的公认方法来解决此问题。任何意见将不胜感激。

4

1 回答 1

1

看来您已经理解了问题和解决方案:使用每个 ADT 内部的静态内存池。

但是,这个池需要被限制到某个最大限制,这应该是硬编码的。本质上,您将在文件范围内将池实现为static缓冲区,并使用计数器变量跟踪“分配”大小。对于您添加的每个项目,您检查计数器与最大限制。

如果您的空间不足,您的程序将知道它并能够以安全的方式处理该错误。但是,永远不应该有空间不足的原因。这意味着你有一个设计错误。您几乎可以肯定能够确保在编译时不会耗尽空间。或者如果不是,至少在代码覆盖测试期间。


指令 4.12 关注堆上的动态内存分配malloc/free。使用这些函数和堆,是术语动态内存分配的 C 事实标准定义。这并不意味着其他任何事情。

动态分配存在多个问题:非确定性分配时间、分段、内存泄漏等。

只要程序行为保持确定性,“动态性”本身就不是问题。安全标准总是关注堆上的动态内存分配,因为它意味着非确定性行为,这是安全关键型软件设计中的一个主要罪过。

对于许多常见的嵌入式系统,例如裸机/RTOS 微控制器应用程序,动态分配根本没有任何意义


所以静态内存池不是“动态内存分配”。否则,堆栈的使用也将被视为“动态内存”,根本无法编写任何有用的软件。

于 2016-02-11T15:00:33.830 回答