Introduction

8601709208_d858ae0ff5_m

If you are serious about software engineering, you will probably be very familiar with the principle of information hiding when writing quality software (which obviously includes firmware) of a nontrivial nature? This principle requires you to reveal as little about the inner working of a block of code as possible. It is a principle that attempts to encapsulate functionality to reduce interdependencies and helps a piece of code to behave as a unit, to be reusable, and helps to prevent changes from affecting other modules. I will get back to this principle in a moment.

How MISRA fits in.

15206555265_b0655713af_m

Now, if you are also predominantly a C programmer, I am sure you are familiar with the MISRA set of programming guidelines. This is a set of best practices originating in the motor industry. Contained in their publication is a list of restrictions, basically isolating language features and programming practices that have historically been shown to carry a higher than normal potential for risk. The one restriction that relates to this article is in the use of dynamic memory where they “require” one not to use it. While there are good reasons for this restriction, this inherently makes it difficult to perform certain types of information hiding – namely hiding the definition of structures.

Though not perfect, MISRA, is a dominant standard in many industries where the C programming language is used, and many projects are compelled to use it. However, some people believe that a few of its rules aren’t so applicable in some contexts. When this is the case, one has the option to exclude that rule together with a published exclusion. Some rules may even hurt some general good programming principals.

For example, in the context of this article, rule 20.4 is sometimes believed to harm the principle of information hiding. How does one declare a storage object (a struct) controlled by a particular block of code (module) and then expect other modules to have restricted access (i.e. not able to directly read or write to members) of that structure without giving that user information about the structure contents and without using dynamic memory? Stated another way, if you give away information about your structure’s size, you also make it easy for other modules to manipulate its contents. This is something that invariably happens – not everyone programs in a disciplined enough manner (they are always a temptation to hack).

I hear cries suggesting the use of memory pools together with opaque pointers. However, the use of memory pools requires you to know the number of instances required at compile time. If you get this wrong, some memory may be wasted, or you may not have enough memory objects and your system could crash unexpectedly due to a deadlock or run sub-optimally. These are unnecessary complications making code reuse difficult and messy. These are unintended consequences – issues that MISRA has possibly not yet been able to address. To preserve a good programming discipline, one may feel compelled to publish a MISRA exclusion, where this rule is explicitly omitted.

To preserve a good programming discipline, one may feel compelled to publish a MISRA exclusion, where this rule is explicitly omitted. However, I will shortly be covering a pattern that should provide the ability to sufficiently preserve information hiding, as well as not requiring a rule exclusion. The pattern also has other advantages, even if you do not use MISRA as a programming guideline.

Privatizing Members:

Private_Property_Sign_on_Fence

Now, the spirit of information hiding is to prevent, or at the very least, to restrict other modules from directly interacting with entities that are encapsulated and are likely to change. This has led me to explore an alternative technique with the goal to accomplish the same thing, but in a much cleaner manner than with the use of memory pools.

The method I have chosen to explore exposes the contents of structures to other modules, but in a way that tries to make it too awkward and painful for those other modules to directly read and write to them. This compels one to maintain a disciplined programming style and to provide proper interfaces to maintain encapsulation.

Now, with the knowledge that each C files get compiled separately and linked later, how about imagining a scenario of having a “lock and key” mechanism where each “private” element can only be accessed if the code doing the accessing is in possession of an appropriate “key”. As you may have guessed, this requires the use of macros.

Now, let’s try to put this “lock and key” metaphor into practice:

Here is the end result (using a simple example):

/*
* rectangle.h
*/

#ifndef RECTANGLE_H_
#define RECTANGLE_H_
#include <stdint.h>

#define MY_OWNER_IS RECTANGLE /*Define who owns this module's private variables*/
#include "common.h"

typedef struct Rectangle_tag
{
PRIVATE_VAR(uint16_t, width);
PRIVATE_VAR(uint16_t, height);
PRIVATE_VAR(uint16_t, *color);
}Rectangle;

Rectangle rectangle_setup(uint16_t height, uint16_t width);
uint16_t get_distance_around_edges(Rectangle *rectangle);
uint16_t get_area(Rectangle *rectangle);

#endif /* RECTANGLE_H_ */

 

Notice that I have used a macro PRIVATE_VAR to define each of the member definitions I want to keep private. I have also used #define MY_OWNER_IS RECTANGLE to invoke a “key” to unlock this macro.

When used legitimately, everything works as if PRIVATE_VAR was not present.

/*
 * rectangle.c
 */
#define RECTANGLE 1
#define THE_MODULE_BEING_BUILT_IS RECTANGLE
#include "rectangle.h"

#include <stdint.h>
Rectangle rectangle_setup(uint16_t height, uint16_t width)
{
   Rectangle my_rectangle = { 0 };
       //to be robust, make sure all values are initialized.
   my_rectangle.height = height;
   my_rectangle.width = width;
   return my_rectangle;
}

uint16_t get_distance_around_edges(Rectangle *rectangle)
{
   uint16_t sum_heights = 2 * rectangle->height;
   uint16_t sum_widths = 2 * rectangle->width;
   return sum_heights + sum_widths;
}

uint16_t get_area(Rectangle *rectangle)
{
   return rectangle->height * rectangle->width;
}

Notice where the “key” is stored (i.e. #define THE_MODULE_BEING_BUILT_IS RECTANGLE) this is used to identify this module as the owner of the structure. As mentioned earlier, notice the complete freedom in using the structure (when used legitimately).

This is a good opportunity to show you how the “lock” mechanism works:

/*
 * common.h
 */

#ifndef COMMON_H_
#define COMMON_H_


#ifdef INDEXING
const int DELIBERATELY_CRASH_THE_COMPILER_IF_INDEXING_IS_DEFINED[-1];  
   /*don't cheat by defining INDEXING to bypass the rules*/
#endif
#if (defined(INDEXING)  /*something only the indexer can see - prevents it confusing what the macros are defined as*/\
    ||(defined(MY_OWNER_IS) && defined(THE_MODULE_BEING_BUILT_IS) /*early termination of test if either not defined*/\
    && (MY_OWNER_IS!=0) && (THE_MODULE_BEING_BUILT_IS!=0) /*must use actual values*/\
    && (MY_OWNER_IS==THE_MODULE_BEING_BUILT_IS))) /*extra check to ensure values are actually the same*/
#   define PRIVATE_VAR(type, item) type item  /*compiling for the owner*/
#else
#   define PRIVATE_VAR(type, item) type item##_IS_PRIVATE_AND_SO_THIS_IS_A_VIOLATION  /*visible to a consumer*/
#endif

#endif /* COMMON_H_ */

Note, if you know MISRA, you may pick up that I am not strictly compliant (rule 19.4) and have cheated by not bracketing the replacement list in any way. Well, for now, unless I find a way to solve this, I will have to list a MISRA exclusion (something that is permitted). I believe this exclusion is worth doing since it is isolated and solves a bigger issue. The meaning is fairly obvious, it is unlikely the macro will be abused in other contexts, and the risks are kept low.

Also, note the steps that have been taken to help prevent the locking mechanism being bypassed by attempts to write hackish code.

Now let us look at a user of this module:

/*
 * consumer.c
 */
#define CONSUMER 2
#define THE_MODULE_BEING_BUILT_IS CONSUMER

#include <stdlib.h>
#include <stdio.h>
#include "rectangle.h"

static Rectangle my_rectangle;

void demonstrate_a_rectangle(void)
{
   my_rectangle = rectangle_setup(10, 15);  
       //the correct way to setup the members
   /*my_rectangle.height = 11;*/            
       //this would just cause the compile to fail. 
       //Even though Eclipse CDT indexing would be happy.

   my_rectangle.height_IS_PRIVATE_AND_SO_THIS_IS_A_VIOLATION = 11; 
       //hmmm - it would really look silly to try to hack the system like this. 
       //It also causes an indexing error in Eclipse!

   printf("The area of my rectangle is %u\r\n", get_area(&my_rectangle));
   printf("The distance around the edge of my rectangle is %u\r\n",
         get_distance_around_edges(&my_rectangle));
}

int main(void)
{
   demonstrate_a_rectangle();
   return EXIT_SUCCESS;
}

Notice how messy and tricky things get when the module tries to directly use the structure in a noncompliant way.

Note to get the indexing to work in Eclipse CDT, you need to add the INDEXING macro to the preprocessor include paths.

Other Solutions

cat-in-window

This is by no means a perfect solution (complexity being the possible main criticism), and I am sure it could be further improved and refined. However, I believe it carries the potential of fewer downsides in many programming scenarios when compared to some other solutions. Perhaps now is a good time to weigh up our position and present some other potential avenues that come to mind:

(1) You could consider adopting an alternative set of quality guidelines. One particularly well-known one originates from NASA’s JPL: The Power of Ten – Rules for Developing Safety Critical Code. This recommends a much simpler, for many people a more rational, and consequently an easier to follow a set of guidelines. This more sensibly allows one to use dynamic memory only during initialization.

The implications of this are that you will probably never end up using “free”, with its associated risks. You can then legitimately use opaque pointers, which you set up at startup. It also strongly advocates Design by Contract (DbC) where one needs to check if dynamic memory allocation is successful and force the system to crash gracefully if the allowance is exceeded. You thereby more elegantly bypass most of the issues associated with dynamic memory, while at the same time also avoid most of the issues associated with forbidding it (as MISRA tries to do).  This means that you can easily verify you have enough dynamic memory during testing (simple to test – the code will crash at startup if you exceed your allowance), and will not unexpectedly run out of dynamic memory while your code is running. Your dynamic memory will never be able to get fragmented since it is never freed. You will also not have indeterminate latencies associated with memory allocations (which can be a problem in real-time systems).

(2) Simply borrow from the Power of Ten approach and allow your code to use dynamic memory during initialization, use opaque pointers, and publish a MISRA exception explaining this.

(3) establishing a set of patterns associated with the use of memory pools. What would be nice would be a way to pre-determine how many instances of a specific object are needed at preprocessing time, and then to allocate enough memory pools to accommodate this. This could be done with the help of a customized preparser/generator, which scans the code, does a count, and then generates a header file containing the required settings.

(4) use opaque pointers in conjunction with alloca (allocation on the stack). However, this has the disadvantage of an indeterminate stack size, complexity, and loss of type safety. It also requires the caller to do the allocation, making the implementation more complicated.

(5) Bypass the C language limitations and MISRA requirements completely by changing to a higher-level object orientated programming languages (notably C++). Note this will only be a real option if you have sufficient resources, are not compelled to use C and MISRA, and do not fear the loss of control a language like C gives you (which works “close to the metal”). The extra abstraction these languages offer at low cost can make constraining memory usage more difficult if not used judiciously.

There are potentially other methods of addressing this challenge more cleanly, which haven’t been explored yet. If you have any further ideas or comments, I would be very interested to hear about them and I am sure many readers would also find them to be useful.


1 Comment

Privatizing Structure Members in C. – Firmware Programming · July 14, 2018 at 5:45 pm

[…] This article has moved. Please visit it by clicking here. […]

Comments are closed.

%d bloggers like this: