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

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?

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.

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

C: How to best handle unsigned integers modulo arithmetic ("wrap-around") when using unsigned operands in calculations

There was this range checking function that required two signed integer parameters:
range_limit(long int lower, long int upper)
It was called with range_limit(0, controller_limit). I needed to expand the range check to also include negative numbers up to the 'controller_limit' magnitude.
I naively changed the call to
range_limit(-controller_limit, controller_limit)
Although it compiled without warnings, this did not work as I expected.
I missed that controller_limit was unsigned integer.
In C, simple integer calculations can lead to surprising results. For example these calculations
0u - 1;
or more relevant
unsigned int ui = 1;
-ui;
result in 4294967295 of type unsigned int (aka UINT_MAX). As I understand it, this is due to integer conversion rules and modulo arithmetics of unsigned operands see here.
By definition, unsigned arithmetic does not overflow but rather "wraps-around". This behavior is well defined, so the compiler will not issue a warning (at least not gcc) if you use these expressions calling a function:
#include <stdio.h>
void f_l(long int li) {
printf("%li\n", li); // outputs: 4294967295
}
int main(void)
{
unsigned int ui = 1;
f_l(-ui);
return 0;
}
Try this code for yourself!
So instead of passing a negative value I passed a ridiculously high positive value to the function.
My fix was to cast from unsigned integer into int:
range_limit(-(int)controller_limit, controller_limit);
Obviously, integer modulo behavior in combination with integer conversion rules allows for subtle mistakes that are hard to spot especially, as the compiler does not help in finding these mistakes.
As the compiler does not emit any warnings and you can come across these kind of calculations any day, I'd like to know:
If you have to deal with unsigned operands, how do you best avoid the unsigned integers modulo arithmetic pitfall?
Note:
While gcc does not provide any help in detecting integer modulo arithmetic (at the time of writing), clang does. The compiler flag "-fsanitize=unsigned-integer-overflow" will enable detection of modulo arithmetic (using "-Wconversion" is not sufficient), however, not at compile time but at runtime. Try for yourself!
Further reading:
Seacord: Secure Coding in C and C++, Chapter 5, Integer Security
Using signed integers does not change the situation at all.
A C implementation is under no obligation to raise a run-time warning or error as a response to Undefined Behaviour. Undefined Behaviour is undefined, as it says; the C standard provides absolutely no requirements or guidance about the outcome. A particular implementation can choose any mechanism it sees fit in response to Undefined Behaviour, including explicitly defining the result. (If you rely on that explicit definition, your program is no longer portable to other compilers with different or undocumented behaviour. Perhaps you don't care.)
For example, GCC defines the result of out-of-bounds integer conversions and some bitwise operations in Implementation-defined behaviour section of its manual.
If you're worried about integer overflow (and there are lots of times you should be worried about it), it's up to you to protect yourself.
For example, instead of allowing:
unsigned_counter += 5;
to overflow, you could write:
if (unsigned_count > UINT_MAX - 5) {
/* Handle the error */
}
else {
unsigned_counter += 5;
}
And you should do that in cases where integer overflow will get you into trouble. A common example, which can (and has!) lead to buffer-overflow exploits, comes from checking whether a buffer has enough room for an addition:
if (buffer_length + added_length >= buffer_capacity) {
/* Reallocate buffer or fail*/
}
memcpy(buffer + buffer_length, add_characters, added_length);
buffer_length += added_length;
buffer[buffer_length] = 0;
If buffer_length + added_length overflows -- in either signed or unsigned arithmetic -- the necessary reallocation (or failure) won't trigger and the memcpy will overwrite memory or segfault or do something else you weren't expecting.
It's easy to fix, so it's worth getting into the habit:
if (added_length >= buffer_capacity
|| buffer_length >= buffer_capacity - added_length) {
/* Reallocate buffer or fail*/
}
memcpy(buffer + buffer_length, add_characters, added_length);
buffer_length += added_length;
buffer[buffer_length] = 0;
Another similar case where you can get into serious trouble is when you are using a loop and your increment is more than one.
This is safe:
for (i = 0; i < limit; ++i) ...
This could lead to an infinite loop:
for (i = 0; i < limit; i += 2) ...
The first one is safe -- assuming i and limit are the same type -- because i + 1 cannot overflow if i < limit. The most it can be is limit itself. But no such guarantee can be made about i + 2, since limit could be INT_MAX (or whatever is the maximum value for the integer type being used). Again, the fix is simple: compare the difference rather than the sum.
If you're using GCC and you don't care about full portability, you can use the GCC overflow-detection builtins to help you. They're also documented in the GCC manual.

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

Resolving a conversion warning in a compound assignment

In my code I have a lot of variable <<= 1; sentences where variable is of type uint16_t. The compiler is spitting a warning saying
conversion to 'uint16_t' from 'int' may alter its value [-Wconversion]
How can I resolve it? I could use a long-form notation like variable = (uint16_t)(variable << 1) - but I'd like to keep the short notation.
Based upon my reading of the standard, you can not get away from this warning for this reason:
uint16_t foo;
foo <<= 1;
is equivalent to
uint16_t foo;
foo = foo << 1;
However, this is caught up in the world of "integer promotion".
The value of the "foo << 1" expression has the type of "foo", however before the left-shift can be conducted it first must go through "integer promotion;" section 6.3.1.1.2 of the C99 standard specifies: "if an int can represent all values of the original type, the value is converted to an int."
This makes the non-implicit version of your code (with extra parentheses) as follows:
uint16_t foo;
foo = ((int)foo) << 1;
Given the warning you are on a system with either 32 or 64 bit ints (or anything bigger than 16, really), you are indeed shoving a bigger value into a smaller one.
One way around this is to be explicit with your casts like so:
uint16_t foo;
foo = (uint16_t)(foo << 1);
But that means that no, you can not use the shorter bitwise shift assignment operator.
If you really are doing this a bunch, consider making a helper function that makes your code clear and compiles cleanly.
void LS(uint16_t &value, int shift) { // LS means LeftShift
*value = (uint16_t)(*value << shift);
}
LS(&foo, 1);
TL;DR: No, you can't use the short operator and avoid that warning at the same time.
You get the warning because variable <<= 1; is equivalent to:
variable = variable << 1;
where the right-hand side has type int, not uint16_t, due to default integer promotions. The best way around this is not to use smaller-than-int types.

Resources