I have implemented a complex state machine with numerous state transitions for a safety SIL 4 system. The back bone for this implementation was done using function pointers. When all was sailing smoothly, the V&V opposed the use of function pointers in a SIL 4 system. Reference- Rule 9 NASA.Misra C 2004 however doesnt say that function pointers cant be used.
Is there any other way to implement complex state machines without any function pointers?
First of all, that NASA document is not canon. Start by asking which law/directive/standard/requirement/document that enforces you to follow the NASA document. If it isn't enforced anywhere (which seems very likely, even at NASA itself), you are not obliged to follow it and you can dismiss the whole thing.
Failing to dismiss the nonsense as nonsense, you can use the usual procedure when hitting a wall with safety standards: the solution is always to document in detail how the stated rule doesn't make sense, and slap them in the face with their own methodology.
So rather than abandoning function pointers, ensure that they are used in a safe manner, through the methods described below.
Since all safety-related design boils down to risk assessment, you'll always have:
With the given (poor) rationale from the NASA document you would justify the safety measure "avoid function pointers" with something like:
That is all rather vague and a questionable risk assessment, but this is what the NASA document boils down to.
Instead of "avoid function pointers" for the above 3 listed hazards, I would suggest using the following safety measures instead:
Defensive programming and assertions
STATES_N
or some such) againstsizeof(func_pointer_array)/sizeof(*func_pointer_array)
.STATE_MACHINE[i]();
whereSTATE_MACHINE
is the array of function pointers, then simply add a run-time check ofi
to ensure that it is always valid.const
pointers if possible (the pointer itself is read-only). If you need to re-assign them in runtime, ensure that they are pointing at a valid function before invoking them.The above kind of state machine is idiomatic and extremely safe, likely much safer than ordinary function calls elsewhere in your code. You'll of course have to ensure that the state transits are done in a safe and reasonable manner, but that's not something that concerns the function pointers.
Avoiding recursion
This is mainly about educating programmers not to use it, function pointers or no function pointers (seems this would have prevented the Toyota bug).
It is neither hard to spot nor avoid recursion, so half-decent code review formalities should be enough to prevent it. No veteran embedded systems programmer, regardless of safety-critical systems experience, will approve of code containing recursion.
You could/should set an in-house design rule stating that all safety-related code must be reviewed and approved by a veteran C programmer with n years of experience of safety-critical program design.
In addition, you should also check for recursion with static analyser tools (even if they aren't able to detect recursion through function pointers). If you have a static analyser that conforms to any version of MISRA-C, this is included.
Regarding unintended recursion, it is avoided with the above mentioned defensive programming methods.
Confusig function pointer syntax
The function pointer syntax in C can admittedly be very confusing, just look at
or some other ridiculous example. It can be solved by always enforcing a
typedef
for function pointer types.(Reference: Les Hatton, Safer C, p184 "From a safety-related viewpoint, the simple answer is that they should never be allowed outside the typedef mechanism.")
There are two different ways you can typedef them, I prefer this:
Because this doesn't hide the pointer behind a typedef, which is generally bad practice. But if you feel more comfortable with the alternative
then that's ok practice too.