MISRA - Prohibited cast of complex integer expression: Signed versus Unsigned - c

I'm at wits end. I can't get MISRA to stop complaining.
typedef unsigned char T_u8;
typedef signed char T_char;
T_u8 value = 0u;
T_char out[some_length];
Begin
out[size_out--] = (( value | 0x30) );
scm.c 320 Note 960: Violates MISRA 2004 Required Rule 12.7, Bitwise operator applied to signed underlying type: |
scm.c 320 Info 734: Loss of precision (assignment) (8 bits to 7 bits)
Sure. Makes sense. I will change it so I am OR'ing the same type.
out[size_out--] = (( value | 0x30u) );
scm.c 320 Info 713: Loss of precision (assignment) (unsigned int to char)
So, with the OR expression, the expression is being promoted to an unsigned int. So, I should cast it to the type it is expecting.
out[size_out--] = (T_char)(( value | 0x30u) );
scm.c 320 Note 960: Violates MISRA 2004 Required Rule 10.3, Prohibited cast of complex integer expression: Signed versus Unsigned
Now what? I don't get it. Why can't I cast it? What do I have to do?
out[size_out--] = (T_char)((T_u8)( (T_u8)value | (T_u8)0x30u) );
scm.c 320 Note 960: Violates MISRA 2004 Required Rule 10.3, Prohibited cast of complex integer expression: Signed versus Unsigned
This didn't help:
out[size_out--] = (( (T_u32)value | (T_u32)0x30) );
scm.c 320 Info 713: Loss of precision (assignment) (unsigned long to char)

The first problem is that you made the literal unsigned, which is indeed required. This however made the expression value | 0x30u an implicit conversion to a different "underlying type" (MISRA-C:2004-only term) of different signedness. Rule 10.1.
You can fix this by forcing an explicit conversion before the | operator is applied:
out[size_out] = (unsigned int)value | 0x30u;
size_out--;
Please note that mixing ++ or -- with other operators in the same expression violates another MISRA rule, for very good reasons, as doing so is dangerous practice.
The above should be enough to sate MISRA-C:2004, though there is still an implicit conversion (lvalue conversion) back to char type. This doesn't violate MISRA but your tool might apparently whine about it still. This is not a MISRA warning:
"Info 713: Loss of precision (assignment) (unsigned long to char)"
It is a rather pedantic warning, though you could add an additional cast to make it go away:
out[size_out] = (T_char)((unsigned int)value | 0x30u);
One of the main purposes of MISRA is to enlighten programmers about how implicit type promotions work in C. They are one of the biggest flaws of the language, and until you study how they work (they are not exactly trivial), you can probably forget about writing MISRA-compliant code. Or bug-free code for that matter. I've tried to explain how the most common ones work here: Implicit type promotion rules.
I would also advise you to upgrade to MISRA-C:2012. It is a more rational document that fixed many problems of MISRA-C:2004. For example, the concept of "underlying type" was replaced.
And finally, you really should start using stdint.h instead of using your own non-standard typedefs.

Related

MISRA: Compound Assignment operators

I have taken over code that has a lot of compound assignment operators in it.
I think that compound operators are not 'really' MISRA compliant.
I can't seem to find any reference to them.
I believe I understand what is happening and that it should actually be separated.
UINT16 A |= B; /* Incorrect */
UINT16 A = (UINT16)((UINT32)A | (UINT32)B); /* Correct */
UINT16 A <<= 1u; /* Incorrect */
UINT16 A = (UINT16)((UINT32)A << (UINT32)1u); /* Correct */
So, my questions are:
Does MISRA frown upon compound assignments?
Is there any kind of quick fix, instead of ignoring the warning?
Thank you,
Does MISRA frown upon compound assignments?
Not as such. The rules for compound assignment are similar to the rules for simple assignment. MISRA speaks of assignment operators in general times, including all of them.
MISRA does however frown upon implicit type promotions, see Implicit type promotion rules. You can't understand these MISRA warnings unless you understand implict promotions.
Is there any kind of quick fix, instead of ignoring the warning?
You can't really fix this without understanding the warning. The only quick fix is to only use uint32_t everywhere and never signed or small integer types, but that isn't always feasible. Your original code would have been compliant if all variables were uint32_t.
In general, the latest MISRA only allows various conversions between types of the same essential type category. Unsigned integers is one such category, signed integers in another, and so on.
It isn't easy to tell how exactly your code violates MISRA without knowing the type of B and sizeof(int). This has nothing to do with compound assignment as such, except that compound assignment operators are a bit cumbersome to work with when it comes to implicit promotions.
MISRA frowns upon assigning the value of an expression (after implicit promotion) to a narrower essential type of the same category or to a different category. In plain English you shouldn't for example assign the result of a uint32_t operation to a uint16_t variable or a signed result to an unsigned variable. This is most often fixed with casting at appropriate places.
Regarding your specific examples, assuming B is uint16_t and the CPU is 32 bit, you get problems with implicit type promotion.
Since A |= B is equivalent to A | B, the usual arithmetic conversions will promote the operands to int in case of 32 bit CPU. So it is a signed 32 bit type.
Assume you had A << 31u - then this would actually have invoked an undefined behavior bug, which the rule seeks to protect against.
Sufficient fixes for MISRA-C compliance:
A = (uint16_t) (A | B); // compliant
A = (uint16_t) ((uint32_t)A << 1u) // compliant

Unpermitted operand to operator '!' [MISRA 2012 Rule 10.1, required]

Observing below Misra warning for below part of code.
Unpermitted operand to operator '!' [MISRA 2012 Rule 10.1, required]
Not sure what could be the fix here to get rid of this warning.
#define C_BYTE unsigned char
C_BYTE SessionStatus;
#define DISCONNECTED 0x10
if((!(SessionStatus & (C_BYTE) DISCONNECTED)))
{
//Do something
}
I tried a few chances but didn't work as below.
1)
if((~(SessionStatus & (C_BYTE) DISCONNECTED)))
{
//Do something
}
2)
if((!(SessionStatus & (C_BYTE) DISCONNECTED)) != 0u)
{
//Do something
}
The reason for the warning is that MISRA-C rule 10.1 expects the operand to the ! && || operators to be "essentially boolean". In your case it is actually an int, because of implicit type promotion rules.
Your 2nd example almost solved it, but you must convert to essentially boolean before applying !. That is:
if(!( (SessionStatus & (C_BYTE)DISCONNECTED) != 0u ))
This is ok since the result of the != operator is to be regarded as essentially boolean. So that code is MISRA-C compliant, but a bit hard to read. I would instead recommend this:
#define DISCONNECTED 0x10u // u suffix makes this essentially unsigned
...
bool disconnected = (bool) (SessionStatus & DISCONNECTED);
if(!disconnected)
By adding the u suffix to the integer constant, it is essentially unsigned, same type category as unsigned char. Therefore the & operation is valid without using any casts. However, we are not allowed to implicitly convert from essentially unsigned to essentially boolean, therefore add the cast to bool.
EDIT
Since SessionStatus & DISCONNECTED is a "composite expression", MISRA doesn't allow the result to be assigned or cast to a different or wider essential type. The rationale is that they fear incompetent programmers who believe that the calculation in for example (uint32_t)(u16a + u16b) is carried out with uint32_t because of the cast, which is of course nonsense. (It would be better to educate the programmers about basic C than to come up with artificial rules, but anyway...)
I'd advise to ignore this rule entirely, but if you can't for whatever reason, here's an alternative fix:
#define DISCONNECTED 0x10u
...
unsigned char disconnected = SessionStatus & DISCONNECTED;
if(!(bool)disconnected)
But of course this is worse code than my first example.

Bitwise shift ( varUint8 >> 7) & 0x01u - Misra complient

I'm troubleshooting some code and I encountered this line
uint8var = ((constUint8[0]) >> 7) & 0x01u;
I was wondering what the correct practice in this is. Is the & 0x01u necessary for proper implementation when writing MISRA compliant code, considering I'm shifting uint8 by 7 digits to the right?
Right-shifting a uint8_t can never be problematic in itself. However, MISRA-C aims to block you from writing bugs caused by implicit integer promotion. In your case constUint8[0] will get implicitly promoted to int which is signed. This will cause various MISRA compliance problems that are easiest avoided by ensuring your code contains no implicit promotions in the first place.
When it comes to shifts, that means casting to a large integer type before shifting:
(uint32_t)constUint8[0] >> 7.
The mask with 0x01u is superfluous and adds no value. It can be safely removed.
To achieve MISRA-C compliance, the best way is to re-write the code like this:
uint8var = (uint8_t) ((uint32_t)constUint8[0] >> 7);
where the (uint8_t) cast ensures that there's no implicit conversion, but that we explicitly go back to the intended type. MISRA-C doesn't allow implicit assignment from larger types to smaller ones.
For more info see Implicit type promotion rules.

MISRA violation "441 - Float cast to non-float "

I am trying to correct the MISRA violation "441 - Float cast to non-float" that is occurring with the following code:
tULong frames = (tULong)(runTimeSeconds * 40.0f);
runTimeSeconds is a float and obviously 40.0f is assigned as a float. Any ideas?
There is a rule (MISRA-C:2004 10.4) stating the value of a complex expression of floating type may only be cast to a narrower floating type.
(runTimeSeconds * 40.0f) is such a so-called complex expression (a MISRA-C:2004 term). To dodge the MISRA violation, you can introduce a temporary variable:
float tmp = runTimeSeconds * 40.0f;
tULong frames = (tULong)tmp; // no complex expression, this is fine
The rationale for this rule is that complex expressions could potentially contain implicit type promotions and similar dangerous things.
MISRA-C:2004 is also worried/paranoid about incompetent programmers who think that changing code like uint8_t u8a, u8b; ... u8a + u8b into (uint32_t)(u8a + u8b) would somehow cause the addition to get carried out as an unsigned 32 bit type.
These rules have been improved in MISRA-C:2012 and are more reasonable there. A cast from a float expression to an unsigned one is fine as per MISRA-C:2012 10.5.
<math.h> has a nice family of functions that round and convert in one call. No cast needed to convert from float to tULong. Below has a (tULong) cast to handle an integer to integer conversion which may be eliminated depending on unposted issues of range and tULong details.
#include <math.h>
// long int lrintf(float x);
// long long int llrint(double x);
// 4 others
tULong frames = (tULong) llrintf(runTimeSeconds * 40.0f);
This rounds rather than truncates like OP's original code.
If the idea is to truncate the result, use the truncf function:
ULong frames = truncf(runTimeSeconds * 40.0f);
That way, your intention is made explicitly.

MISRA warning 12.4: integer conversion resulted in truncation (negation operation)

In a huge macro I have in a program aimed for a 16-bit processor, the following code (simplified) appears several times:
typedef unsigned short int uint16_t;
uint16_t var;
var = ~0xFFFF;
MISRA complains with the warning 12.4: integer conversion resulted in truncation. The tool used to get this is Coverity.
I have checked the forum but I really need a solution (instead of changing the negation by the actual value) as this line is inside a macro with varying parameters.
I have tried many things and here is the final attempt which fails also:
var = (uint16_t)((~(uint16_t)(0xFFFFu))&(uint16_t)0xFFFFu);
(the value 0xFFFF is just an example. In the actual code, the value is a variable which can take whatever value (but 16 bits))
Do you have any other idea please? Thanks.
EDIT:
I have tried then to use 32bits value and the result is the same with the following code:
typedef unsigned int uint32_t;
uint32_t var;
var = (uint32_t)(~(uint32_t)(0xFFFF0000u));
Summary:
Assuming you are using a static analyser for MISRA-C:2012, you should have gotten warnings for violations against rule 10.3 and 7.2.
Rule 12.4 is only concerned with wrap-around of unsigned integer constants, which can only occur with the binary + and - operators. It seems irrelevant here.
The warning text doesn't seem to make sense for neither MISRA-C:2004 12.4 nor MISRA-C:2012 12.4. Possibly, the tool is displaying the wrong warning.
There is however a MISRA:2012 rule 10.3 that forbids to assign a value to a variable that is of a smaller type than intended in the expression.
To use MISRA terms, the essential type of ~0xFFFF is unsigned, because the hex literal is of type unsigned int. On your system, unsigned int is apparently larger than uint16_t (int is a "greater ranked" integer type than short in the standard 6.3.1.1, even if they are of the same size). That is, uint16_t is of a narrower essential type than unsigned int, so your code does not conform to rule 10.3. This is what your tool should have reported.
The actual technical issue, which is hidden behind the MISRA terms, is that the ~ operator is dangerous because it comes with an implicit integer promotion. Which in turn causes code like for example
uint8_t x=0xFF;
~x << n; // BAD, always a bug
to invoke undefined behavior when the value 0xFFFFFF00 is left shifted.
It is therefore always good practice to cast the result of the ~ operator to the correct, intended type. There was even an explicit rule about this in MISRA 2004, which has now merged into the "essential type" rules.
In addition, MISRA (7.2) states that all integer constants should have an u or U suffix.
MISRA-C:2012 compliant code would look like this:
uint16_t var;
var = (uint16_t)~0xFFFFu;
or overly pedantic:
var = (uint16_t)~(uint16_t)0xFFFFu;
When the compiler looks at the right side, first it sees the literal 0xFFFF. It is automatically promoted to an integer which is (obvious from the warning) 32-bit in your system. Now we can imagine that value as 0x0000FFFF (whole 32-bit). When the compiler does the ~ operation on it, it becomes 0xFFFF0000 (whole 32-bit). When you write var = ~0xFFFF; the compiler in fact sees var = 0xFFFF0000; just before the assign operation. And of course a truncation happens during this assignment...

Resources