MISRA: Compound Assignment operators - c

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

Related

MISRA C: Type casting and <<, & bit-wise operators error

I've been having a lot of trouble with MISRA when doing << and & operations.
Definitions of types for context
typedef uint32_t uint32;
typedef volatile uint32* canreg_txrx_pointer;
canreg_txrx_pointer canreg_txrx;
uint8_t valueRead, value;
#define CAN_DIR_BIT_POS ((uint8_t)2U)
#define CAN_OUT_BIT_POS ((uint8_t)1U)
#define CAN_IN_BIT_POS ((uint8_t)0U)
When trying to perform a series of << and & operations on the registers, I continually get the error #1397-D (MISRA-C:2004 10.5/R) If the bitwise operators ~ and << are applied to an operand of underlying type unsigned char or unsigned short, the result shall be immediately cast to the underlying type of the operand
An example that doesn't pass the misra check and then an example that does is given below
*canreg_txrx = (uint32)((*canreg_txrx & (~(uint32)(1U << CAN_OUT_BIT_POS))) | (uint32)(value << CAN_OUT_BIT_POS)); //doesn't pass MISRA
valueRead = (uint8_t)(((uint8_t)*regToOperateOn & (uint8_t)(1U << CAN_OUT_BIT_POS)) >> CAN_OUT_BIT_POS); //passes MISRA
I've tried multiple changes to the offending line where none of them have resulted in MISRA letting it through (except randomly where it just gives me no warnings) to the point where I decided to cast everything and that still doesn't work
*canreg_txrx = (uint32)((*canreg_txrx & (uint32)(~(uint32)((uint32)1U << (uint32)CAN_OUT_BIT_POS))) | (uint32)((uint32)value << (uint32)CAN_OUT_BIT_POS)); //doesn't pass MISRA
I'm really confused on how to fix this code so that it will pass MISRA as this bitwise logic is used in multiple places and all of them don't pass. I assumed that if everything is cast to the same type then there should really be no issue since it's all operating at the same type but for some reason that doesn't work.
I have never used Misra but I find your code hard to read with all that noise of typedefs, casts and parenthesis. My suggestion would be to simplify and split the problem into smaller parts along these lines:
*canreg_txrx = (uint32)((*canreg_txrx & (~(uint32)(1U << CAN_OUT_BIT_POS))) | (uint32)(value << CAN_OUT_BIT_POS)); // =>
*canreg_txrx &= ~(1U << CAN_OUT_BIT_POS);
*canreg_txrx |= value << CAN_OUT_BIT_POS; // maybe =>
#define BIT_CLEAR(val, pos) ((val) &= ~(1U << (pos)))
BIT_CLEAR(*canreg_txrx, CAN_OUT_BIT_POS);
*canreg_txrx |= value << CAN_OUT_BIT_POS; // *
'*' If value is a bit, then this is just bit set, otherwise can't think of good name.
Then run it through Misra and only fix what it complains about.
MISRA-C is a bit confused since it insists on a cast to "underlying type" (MISRA-C:2004 term) after the shift has been done. I prefer to do the cast to a large unsigned type before the shift, since that rules out all problems that can happen.
What these rules strive to prevent is an accidental conversion to a signed type through Implicit type promotion rules followed by something like a bit shift, which could be dangerous and cause various bugs, including change of signedness, accidental sign extension, undefined behavior upon left shifting signed values, impl.defined behavior upon right shifting them, and so on.
In your case, you get these problems specifically because you are not casting the result of the ~ to the underlying type here: ~(uint32)(1U << CAN_OUT_BIT_POS)). It appears that your static analyser is giving a false positive, since the underlying type here appears to be uint32_t. There is no smaller type to account for unless since you appear to have have 32 bit integers (since you have 32 bit CAN registers) , but the tool might not know that your integers are 32 bits, in which case 1U could have been a 16 bit value.
Otherwise, maybe the tool is getting confused because you use confused casts when defining those macros... but for the shift operators specifically, the type of the right operand does not matter (though it's promoted too).
In this particular case, none of this should be dangerous since you expect unsigned 32. The warnings, the casts, everything - it's just noise, turning your code brittle and unreadable.
I'd suggest you salvage the code in the following manner:
Get rid of all the uint8 casts from the macros, that's just noise and potentially causing problems.
Get rid of the home-brewed uint32 etc types and use standard C uint32_t. typedef uint32_t uint32; is rotten code that shouldn't exist in any C program. Use the existing industry standards, don't invent new ones.
Don't hide pointers behind typedefs, that's very dangerous practice which makes the code hard to read.
Get rid of superfluous casts. Assuming this is a 32 bitter, you shouldn't cast 1U types to uint32_t since they are the same type already.
Break up unreadable lines into several expressions. For example we can do const uint32_t mask = ~(1U << CAN_OUT_BIT_POS);. There should be no need to cast since the underlying type is already uint32_t. Your MISRA checker might be too dumb to realize that you have 32 bit integers though, so you might have to add a cast (uint32_t)~ .... Not for MISRA-C:2004 compliance but to silence a potentially dumb tool.
In case you just need to cast to silence a particular tool, you should make an explicit comment about that: /* this cast just to silence BrokenAnalyser from Bugworks */. To show that you know what you are doing and that you separate false positives from actual necessary casts.
Another valid concern of MISRA-C is that you shouldn't be doing multiple accesses to volatile registers in the same expression, since this introduces unsequenced side effects, plus you can't really tell when and where on that line the actual register access happens, plus it blocks compiler optimizations. This is another MISRA violation that you have not yet spotted. This can also be solved by breaking up the long expression into several.
One example:
const uint32_t mask = ~(1U << CAN_OUT_BIT_POS);
uint32_t txrx = *canreg_txrx; // volatile access on a line of its own
txrx = (txrx & mask) | ((uint32_t)value << CAN_OUT_BIT_POS);
*canreg_txrx = txrx;
The middle txrx line will get optimized and in the machine code you'll just get a few instructions anyway. This should be MISRA-C:2004 and 2012 compliant, far as I can tell. This also doesn't shift the implicitly promoted value and then cast afterwards.

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 - Prohibited cast of complex integer expression: Signed versus Unsigned

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.

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...

C, compound assignment - arithmetic operation, conversion may loose information

Is there a way to write the operation short and suppress the warning?
BYTE data[10];
int i = 0;
int offset = 0;
for (i = 0; i < 7; i++) {
// some code
data[offset] |= (1 << i); // WARNING: conversion may loose information
}
my attempts:
data[offset] |= (BYTE) (1 << i); // failed
data[offset] |= (1 << (BYTE) i); // failed
Compiler: TIA-V13 WinCC from Siemens
Solution: No compound assignment operators!
You did not define BYTE; I'll assume it is identical to stdint.hs uint8_t (which should always be preferred to homebrew types).
a |= b (roughly) translates to a = a | b, including integer promotions here as part of the usual arithmetic conversions. For the types given this means a is converted to int before the operation is performed, yielding an int result. The final assignment will truncate this int for the assignment, possibly loosing information (likely the sign), because int is at least 16 bits wide.
Casting b does not help, because the conversion is done for the operation and you have to cast the result.
The transformation is also the solution:
uint8_t a;
a = (uint8_t)(a | b);
Explicitly tells the compiler you know what you do and to shut up. Just make sure you really know what you do!
This is not very elegant, but the only way to suppress the warning. OTOH the behaviour is arithmetically consistent with the simple assignment-version.
Edit: You should use unsigned integer constants when shifting where possible. Even more, as you operate on unsigned variables anyway. As a general rule, try to avoid mixing signed and unsigned operands. If that is not possible make sure you know what is going on and catch all invalid cases.
Edit2: For some implementations/signed integer representations and some combinations for types and operations, it is possible to prove no information can be lost, thus the warning is obsolete. However, it seems this would require knowledege of machine details which might not be available at the stage the warning is generated.
Maybe the C standard should have defined the compound assignment to implicitly include the final cast. That would not be the only legacy. OTOH, this behaviour might have generated confusion in the other direction to people which were not aware of this (note that in C an assignment yields a result!). Which is the lesser of two evils?

Resources