Misra C Rule 12.2 - false positive warning? - c

My CCS 6.1 ARM compiler (for LM3Sxxxx Stellaris) throws a warning :
"MISRA Rule 12.2. The value of an expression shall be the same under any order of evaluation that the standard permits"
for following code:
typedef struct {
...
uint32_t bufferCnt;
uint8_t buffer[100];
...
} DIAG_INTERFACE_T;
static DIAG_INTERFACE_T diagInterfaces[1];
...
DIAG_INTERFACE_T * diag = &diagInterfaces[0];
uint8_t data = 0;
diag->bufferCnt = 0;
diag->buffer[diag->bufferCnt++] = data; // line where warning is issued
...
I don't see a problem in my code. Is it false positive or my bug?

Put diag->bufferCnt++ in a separate statement (as it is also advised by Hans in OP comments) and the warning should not appear.
But regarding MISRA rule 12.2 I see no violation of 12.2 (there is a single sequence point in your statement and no unspecified behavior) in your program and I think it's a bug in your MISRA software.
For information there is also an advisory 12.13 rule in MISRA that says:
(MISRA-C:2004, 12.13) "The increment (++) and decrement (--) operators should not be mixed with other operators in an expression"
The problem with MISRA is their terminology use is far from perfect, for 12.3, while -> or = are C operators, in the explanation they then seem to talk only about arithmetic operators...

Although you don’t indicate it, this is MISRA-C:2004, Rule 12.2, and is now MISRA-C:2012 Rule 13.2. As oauh says, this has nothing to do with "order of evaluation”.
I highly recommend referring to MISRA-C:2012 even if you are required to be MISRA-C:2004 compliant, having MISRA-C:2012 around helps, because it has clarified many of the guidelines, including additional rationale, explanations and examples.
You should not be using a compiler to solely check for MISRA-C compliancy, its nice, but compilers #1 goal is not to warn you about all the traps and pitfalls of the language it is dedicated to take advantage of (optimization). They're not very precise either, as in this case. Also, there are many undefined behaviors across translation units, compilers cannot warn about. Its best to also use a dedicated MISRA Static analysis tool, one that is not compiler specific, but that warns about all unpredictable constructs from the ISO C standards point of view, not a particular implementation.
As oauh also said, this is a violation of MISRA-C:Rule 12.13, which is now MISRA-C:2012 Rule 13.3 which has been relaxed to permit ++ and -- to be mixed with other operators, provided that the ++ or -- is the only source of side-effects (in your case the assignment is also a side effect in C terminology).
The Rule is not critical, i.e. its well defined behavior, but the different values resulting from the prefix version and the postfix version can cause confusion, thus it is “advisory” meaning no formal deviation is required (again, a decent MISRA-C tool would allow you to suppress this particular violation).

Related

What is the rationale for "semantics violation does not require diagnostics"?

Follow-up question for: If "shall / shall not" requirement is violated, then does it matter in which section (e.g. Semantics, Constraints) such requirement is located?.
ISO/IEC 9899:202x (E) working draft— December 11, 2020 N2596, 5.1.1.3 Diagnostics, 1:
A conforming implementation shall produce at least one diagnostic message (identified in an
implementation-defined manner) if a preprocessing translation unit or translation unit contains a
violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. Diagnostic messages need not be produced in other circumstances.
Consequence: semantics violation does not require diagnostics.
Question: what is the (possible) rationale for "semantics violation does not require diagnostics"?
A possible rationale is given by Rice's theorem : non-trivial semantic properties of programs are undecidable
For example, division by zero is a semantics violation; and you cannot decide, by static analysis alone of the C source code, that it won't happen...
A standard cannot require total detection of such undefined behavior, even if of course some tools (e.g. Frama-C) are sometimes capable of detecting them.
See also the halting problem. You should not expect a C compiler to solve it!
The C99 rationale v5.10 gives this explanation:
5.1.1.3 Diagnostics
By mandating some form of diagnostic message for any program containing a syntax error or
constraint violation, the Standard performs two important services. First, it gives teeth to the
concept of erroneous program, since a conforming implementation must distinguish such a program from a valid one. Second, it severely constrains the nature of extensions permissible to
a conforming implementation.
The Standard says nothing about the nature of the diagnostic message, which could simply be
“syntax error”, with no hint of where the error occurs. (An implementation must, of course,
describe what translator output constitutes a diagnostic message, so that the user can recognize it as such.) The C89 Committee ultimately decided that any diagnostic activity beyond this level is
an issue of quality of implementation, and that market forces would encourage more useful
diagnostics. Nevertheless, the C89 Committee felt that at least some significant class of errors
must be diagnosed, and the class specified should be recognizable by all translators.
This happens because the grammar of the C language is context-sensitive and for all the languages that are defined with context-free or more complex grammars on the Chomsky hierarchy one must do a tradeoff between the semantics of the language and its power.
C designers chose to allow much power for the language and this is why the problem of undecidability is omnipresent in C.
There are languages like Coq that try to cut out the undecidable situations and they restrict the semantics of the recursive functions (they allow only sigma(primitive) recursivity).
The question of whether an implementation provides any useful diagnostics in any particular situation is a Quality of Implementation issue outside the Standard's jurisdiction. If an implementation were to unconditionally output "Warning: this program does not output any useful diagnostics" or even "Warning: water is wet", such output would fully satisfy all of the Standard's requirements with regard to diagnostics even if the implementation didn't output any other diagnostics.
Further, the authors of the Standard characterized as "Undefined Behavior" many actions which they expected would be processed in a meaningful and useful fashion by many if not most implementations. According to the published Rationale document, Undefined Behavior among other things "identifies areas of conforming language extension", since implementations are allowed to specify how they will behave in cases that are not defined by the Standard.
Having implementations issue warnings about constructs which were non-portable, but which they would process in a useful fashion would have been annoying.
Prior to the Standard, some implementations would usefully accept constructs like:
struct foo {
int *p;
char pad [4-sizeof (int*)];
int q,r;
};
for all sizes of pointer up to four bytes (8-byte pointers weren't a thing back then), rather than squawking if pointers were exactly four bytes, but some people on the Committee were opposed to the idea of accepting declarations for zero-sized arrays. Thus, a compromise was reached where compilers would squawk about such things, programmers would ignore the useless warnings, and the useful constructs would remain usable on implementations that supported them.
While there was a vague attempt to distinguish between constructs that should produce warnings that programmers could ignore, versus constructs that might be used so much that warnings would be annoying, the fact that issuance of useful diagnostics was a Quality of Implementation issue outside the Standard's jurisdiction meant there was no real need to worry too much about such distinctions.

Why are const qualified variables accepted as initializers on gcc?

When compiling this code in latest verson of gcc (or clang) with -std=c17 -pedantic-errors -Wall -Wextra
static const int y = 1;
static int x = y;
then I get no compiler diagnostic message even though I'm fairly sure that this is not valid C but a constraint violation. We can prove that it is non-conforming by taking look at C17 6.7.9/4:
Constraints
...
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
Then the definition about constant expressions, in this case an integer constant expression (6.6):
An integer constant expression shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, _Alignof expressions, and floating constants that are the immediate operands of casts.
And then finally the definition about integer constants (6.4.4.1/2):
An integer constant begins with a digit, but has no period or exponent part. It may have a prefix that specifies its base and a suffix that specifies its type.
Thus a const int variable is not an integer constant nor is it an integer constant expression. And therefore not a valid initializer. This has been discussed before (for example here) and I think it's already established that this is non-conforming. However, my question is:
Why did gcc chose to be non-compliant even in strict mode?
clang has apparently always been non-compliant, but gcc changed from being compliant in version 7.3 to non-compliant in version 8.0 and above. gcc 7.3 and earlier gives "error: initializer element is not constant" even in default mode without -pedantic-errors.
Some sort of active, conscious decision seems to have been made regarding this message. Why was it removed entirely in gcc and why didn't they leave it as it was when compiling in strict mode -std=c17 -pedantic-errors?
Why did gcc chose to be non-compliant even in strict mode?
Inasmuch as the question as posed is directed to the motivation of the developers, the only information we have to go on as third parties comes from the public development artifacts, such as GCC bugzilla, repository commit messages, and actual code. As was pointed out in comments, the matter is discussed in the Bugzilla comment thread associated with the change.
The Bugzilla discussion appears to show that the developers considered the standard's requirements in this area, albeit in a somewhat perfunctory manner. See in particular comments 9 and 10. They raise paragraph 6.6/10 of the language specification:
An implementation may accept other forms of constant expressions.
They do not subject this to any particular scrutiny, and I read the comments more as seeking a justification for the change than as a thoughtful inquiry into GCC conformance considerations.
Thus, they made the change because they wanted to implement the feature request, and they found sufficient (for them) justification in the language of the standard to consider the altered behavior to be consistent with language constraints, therefore not requiring a diagnostic.
There is also an implied question of whether recent GCC's silent acceptance of the declaration forms presented in fact violates conforming processors' obligation to diagnose constraint violations.
Although it is possible to interpret 6.6/10 as allowing implementations to accept any expressions they choose as conforming to the requirements for any kind of constant expression, that seems fraught. Whether a given piece of code satisfies the language's constraints should not be implementation dependent. Either of these points of interpretation, if accepted, would resolve that problem:
6.6/10 should be interpreted as expressing a specific case of the general rule that a conforming implementation may accept non-conforming code, without implying that doing so entitles the processor to treat the code as conforming.
6.6/10 should be interpreted as permitting processors to interpret more expressions as "constant expressions" than those described in the preceding paragraphs, but that has no bearing on the definitions of the specific kinds of constant expressions defined in those paragraphs ("integer constant expressions" and "arithmetic constant expressions").
Those are not mutually exclusive. I subscribe to the latter, as I have written previously, and I tend to favor the former as well.

MISRA 11.3: cast from int to pointer

I have one question on how to solve MISRA 2004 11.3 violation.
The code is as follows:
tm_uint8 read( tm_uint8* data)
{
data[0] = *((tm_uint8*)0x00003DD2);
data[1] = *((tm_uint8*)0x00003DD3);
data[2] = *((tm_uint8*)0x00003DD4);
}
I want to write the value stored at the physical address. It compiles but I have a MISRA violation for 11.3. I want to solve it. Can anyone help me with that?
The rationale behind this rule is that MISRA worries about misaligned access when casting from an integer to a pointer. In your case, I assume tm_uint8_t is 1 byte, so alignment shouldn't be an issue here. In that case, the warning is simply a false positive and you can ignore it. This is an advisory rule, so you don't need to raise a deviation.
There is no other work-around, except never working with absolute addresses. Which is most likely not an option here. As you can tell, this rule is very cumbersome when writing hardware-related code, there is just no way such code can follow the rule.
Note: MISRA-C:2004 Rule 11.3 is equivalent to MISRA C:2012 Rule 11.4
It is accepted that some MISRA C/C++ Rules may cause a violation to be raised, in situations where the method used is necessary.
Because of this, MISRA C provides a mechanism for Deviating a Rule - and this would be the appropriate route for you to follow... please do not try and find a way around the Rule using "clever" code!
As highlighted by this question, accessing specific memory (and/or I/O devices) is one particular case. In fact, one of the examples included in MISRA C:2012 shows this exact use case as being non-compliant with the Rule.
In 2016, the MISRA C Working Group published additional guidance on Compliance, including enhancing the Deviation process... this gives help on what is a justifiable Deviation - and accessing hardware is one of those!
In due course, it is planned to provide more "layered" guidance... but that will not be immediate.
[Please note profile for disclaimer]

MISRA C rule 12.2

I am new to MISRA rules concepts. I have a rule 12.2 warning saying
The value of an expression shall be the same under any order of
evaluation that the standard permits (MISRA C 2004)
on the following C code:
PtToStack->Entry[PtToStack->top] = e ;
where PtToStack is pointer to stack, Entry is array in the stack structure and top variable is a field of the stack structure.
e has the same type of Entry.
Could any one help me to understand the warning?
This rule from MISRA-C:2004 (older standard) is concerning the order of evaluation of operands, in expressions where the order is not specified. There are plenty of examples and education material regarding the issue, below rule 12.2.
In your expression, there are no issues with unspecified order of evaluation. Therefore, the warning is incorrectly generated by your tool. Your static analyser is bad, file a bug report with the tool vendor.

Issues covered by rule 3.1 of misra c 2004 "Implementation-defined behavior documented"

In this rule you have to go to ISO/IEC 9899:1990 Appendix G and study each case of Implementation defined behavior to document them.
It's a difficult task to determine what are the manual checks to do in the code.
Is there some kind of list of manual checks to do because of this rule?
MISRA-C is primarily concerned with avoiding unpredictable behavior in the C language, those “traps and pitfalls” (such as undefined and unspecified behavior) all C developers should be aware of that a compiler will not always warn you about. This includes implementation-defined behavior, where the C standard specifies the behavior of certain constructs after compilation can vary. These tend to be less critical from a safety point of view, provided the compiler documentation describes its intended behavior as required by the standard.
That is, for each specific compiler the behavior is well-defined, but the concern is to assure the developers have verified this, including documenting language extensions, known bugs in the compiler (and build chain) and workarounds.
Although it is possible to manually check C code fully for MISRA􏰀-C compliancy, it is not recommended. The guidelines were developed with static analysis tools in mind. Not all guidelines can be fully checked by tools, but the better MISRA-C tools (be careful in your evaluations, there are not many “good” ones), will at least assist where it can identify automatically where code relies on implementation-specific behavior. This includes all the checks required in Rule 3.1., where implementation-defined behavior cannot be completely checked by a tool, then a manual review will be required.
Also, if you are starting a new MISRA-C project, I highly recommend referring to MISRA-C:2012, even if you are required to be MISRA-C:2004 compliant. Having MISRA-C:2012 around helps, because it has clarified many of the guidelines, including additional rationale, explanations and examples. The standard (which can be obtained at misra-c.com ) lists the C90 and C99 implementation-defined behaviors that are considered to have the potential to cause unintended behavior. This may or may not overlap with guidelines that address implementation-defined behaviors that MISRA-C is specifically concerned about.
First of all, the standard definition of implementation-defined behavior is: specific behavior which the compiler must document. So you can always refer to the compiler documentation whenever there is a need to document how a certain implementation-defined behavior is implemented.
What's left to you to do then is to document where the code relies on implementation-defined behavior. This is preferably done in source code comments.
Spontaneously, here are the most important things which you need to look for in the code. The list is not including those cases that are already covered by other MISRA rules (for example signedness of char).
The size of all the integer types. The size of int being most important, as it determines which type that is given to integer literals, C "boolean" expressions, implicitly promoted integers etc etc.
Obscure integer formats that aren't standard two's complement.
Any reliance on endianess.
The enum type format.
The floating point format.
Pointer to integer conversions, in case they are obscure on the given system.
Behavior of function inlining and the register keyword, if these are used.
Alignment issues including struct padding. Reliance on the size of a struct/union.
#include paths, in case they are obscure. Particularly if they are absolute and not relative.
Bitwise operators mixed with signed types (in most cases this is a bug or design mistake).

Resources