MC/DC Coverage and Short Circuit Explained

MC/DC Coverage and Short Circuit Explained
Modified Condition/Decision Coverage (MC/DC) is a code coverage metric that is referred to in many safety standards as the highest level of quality. It was first defined to provide an intermediate metric between condition and multiple-condition coverage for integrated circuits. Whereas plain condition coverage was considered too simple, the Multiple-Condition Coverage has the drawback of a potential exponential explosion of test cases. MC/DC is a compromise that guarantees a number of test cases that merely grows linearly with the number of conditions, while still achieving a higher level of confidence compared to basic Condition Coverage.
Here is the DO-178C standard definition of MC/DC:
Every point of entry and exit in the program has been invoked at least once, every condition in a decision in the program has taken all possible outcomes at least once, every decision in the program has taken all possible outcomes at least once, and each condition in a decision has been shown to independently affect that decision’s outcome.
A condition is shown to independently affect a decision’s outcome by: (1) varying just that condition while holding fixed all other possible conditions or (2) varying just that condition while holding fixed all other possible conditions that could affect the outcome.
The sentence in bold was added on top of the definition in DO-178B and precisely permits the behavior of a short circuit. The short circuit (also called passive evaluation) does not exist in integrated circuits because it corresponds to a software optimization which consists of skipping the evaluation of some boolean expressions which do not influence the decision outcome. This is why the extension of this definition was not present in earlier versions of the standard.
To understand the short circuit, we can take a small trivial sample “X = A and B”. If we know that A or B is false, the other term of the expression does not need to be evaluated and we directly know that X is false. This has an impact on the expression’s truth table and permits to generate a more compact table:
 A B A and B False – False – False False True True True

The minus sign (-) is ambiguous in this table because it traditionally means “don’t care”, but for programming languages which implement the short circuit, it means “don’t evaluate”. This is a big difference as the evaluation of an expression can have side effects. Also, due to the fact that the order of evaluation is from left to right, this table is for C, C++ and C#:

 A B A and B False Don’t evaluate False True False False True True True

Let see a practical sample of the new definition’s impact: If we take the expression “X = ( A or B ) and C” we will get the following truth table:

 A B C (A or B) and C True Don’t evaluate False False False True False False True Don’t evaluate True True False True True True False False Don’t evaluate False
Let’s take the test vector A=False, B=True and C=True. If we want to find a test vector which toggles B and which accounts for MC/DC coverage we can only choose the last one A=False and B=False because:

1. All other vectors are modifying the other conditions. So A is not allowed to be True and C is not allowed to be False. This is the constraint introduced by the point (1) of the MC/DC definition.
2. The point (2) allows that conditions which have no impact to the output can be ignored. This applied to the test vector A=False and B=False.

Without the point (2), it would be necessary to create a test vector which fits A=False, B=False and C=True which is not possible if it is not allowed to evaluate C.

To be more concrete, let’s analyze a small C++ sample which uses a short circuit and shows us why the new clause (2) applies to it:

bool log( const char *text )
{
static FILE *f = NULL;
if (
( f || f=fopen("logfile.txt","a+") )
&&
fputs( text, f ) != EOF
)
{
fflush( f );
return true;
}
else
return false;
}

This code simply opens a log file (if not already opened) and writes text into it.

The truth table of the ‘if‘ statement is:

 f f=fopen(“logfile.txt,”a+”) fputs(text,f)!=EOF if statement True Don’t evaluate False False False True False False True Don’t evaluate True True False True True True False False Don’t evaluate False

This simple example illustrates why toggling all conditions is not allowed: we use the same test pattern as above: ‘f’=False, ‘f=fopen(“logfile.txt,”a+”)‘=True and ‘fputs(text,f)!=EOF‘=True. Then we decide to only toggle ‘f=fopen(“logfile.txt,”a+”)‘. The test pattern without short cut would be: ‘f’=False, ‘f=fopen(“logfile.txt,”a+”)‘=False and ‘fputs(text,f)!=EOF‘=True. The programmer has used the short circuit facility of C++ to avoid a crash when calling fputs with a NULL pointer. That’s why it is necessary to apply the new clause (2) of the DO-178C and omit the evaluation of ‘fputs(text,f)!=EOF‘.