|
I asked the following question on Stack Overflow and received a helpful answer which I have integrated into my question here. (http://stackoverflow.com/questions/35341...12-and-4-8) The following is an extended version of the question I asked. This question relates to coding in ISO C99 following the MISRAC:2012 guidelines.
I am looking for guidance on Dir 4.8 “If a pointer to a structure or union is never dereferenced within a translation unit, then the implementation of the object should be hidden†in conjunction with Dir 4.12 “Dynamic memory allocation shall not be usedâ€.
When implementing an Abstract Data Type in C it is common to refer to the ADT using a handle that is a pointer to a structure describing the internal state of the ADT. This can be done using an opaque pointer as per Dir 4.8 with the benefit that the internal details remain hidden from the user.
Generally more than one of these ADTs could exist so there must be a way to create mulitple handles. This can be solved by allocating memory for the internal details referenced by the handle in an initialisation function, however, this is not allowed under Dir 4.12.
Another option is that the initialisation routine receives a pointer to a statically allocated handle provided by the user, however, this cannot be accomplished using opaque pointers.
I illustrate the problem below.
Module.h
Code: /* Module handle is only available to the world as an incomplete type.
This allows us to satisfy MISRAC 2012 Dir 4.8.*/
struct module;
typedef struct module module_t;
Module.c
Code: #include "module.h"
struct module
{
uint8_t value;
};
module_t* module_get_a_handle(void)
{
/* MISRAC 2012 Dir 4.12 disallows dynamic memory allocation.*/
return (module_t*)malloc(sizeof(struct module));
}
User.c
Code: #include "module.h"
module_t* module_handle;
module_handle = module_get_a_handle();
One solution is to use a statically allocated pool of handles within the ADT that are made available to client code. This solution seems to be technically compliant; however, it seems that the concept of dynamic memory allocation still exists here. I would argue that although the handles are statically allocated, it cannot be determined by the compiler during compilation whether there will be enough handles available for the software to function correctly.
I understand the argument that if a module runs out of statically allocated handles then it is a design error. However, it seems advantageous if the compiler can also determine in many cases whether there is enough space at compile time (this forces developers to fix the problem early rather than discovering it in code reviews or testing later on). The compiler can determine the problem if a statically allocated handle is passed from client code to the ADT as it is then clear to the compiler how many handles in total will be required by the SW. This also feels like a cleaner separation of concerns to me. Is it the responsibility of the ADT to know how many handles may be required, and if so does this not complicate any module reuse somewhat?
Additionally, in my case we are defining a company template that all new modules should be based on. The level of C proficiency of our developers ranges from beginner to intermediate. I am concerned that requiring each ADT to manage a static buffer of handles will be seen as overly complicated (and therefore a maintenance issue) and be met with resistance. Clearly raising the C skill level of developers is desirable but this will not happen immediately.
My solution to this problem would be to deviate on the advisory directive 4.8 and use non-opaque pointers and a strong naming convention that makes it clear to users that the internal details of the ADT must not be changed.
I am curious whether there is a well accepted method to solve this issue that satisfies Dir 4.8, and Dir 4.12, and does not break any other MISRAC:2012 rules. Is it common practice to define a static array of handles in every ADT?
I'm also interested in a critique of
a) deviating Dir 4.8 and using a naming convention that makes it obvious that the handle points to internal details that should not be accessed directly coupled with educating developers not to access the internals details.
b) deviating Dir 4.12(!) to allow dynamic memory allocation in a well defined initialisation phase only. For b), I believe that if it can be shown that the memory allocation is deterministic in this initialisation phase and the initialisation phase can be tested at a system level successfully once then it follows that the memory allocation will always be successful.
My preference is to deviate on the advisory directive 4.8 in this particular case as it seems to have the least disadvantages.
Any comments would be greatly appreciated.
|