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

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.

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

How can I make my code in compliance with MISRA 2012 RULE10.4

if(fn1()) //Line 1
{
a++;
}
Here the return type of function fn1 is uint8_t. The function returns only values 0 or 1.
PC Lint throws error for line 1 says "Mismatched essential type categories for binary operator" [RULE 10.4 required]
Rule 10.4 says "Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category"
MISRA-C doesn't allow implicit checks against zero - all inputs to conditional statements must be "essentially boolean", which is what you get if you explicitly use logical operators like ==.
In addition, MISRA-C has various rules blocking you from mixing "essenitally signed" and "essentially unsigned" in the same expression, and thereby relying on implicit type promotions. So you can't write if (fn1() == 1) for that reason, since 1 is a signed type and there's also a rule requiring all integer constants to have u suffix.
So one possible fix is if (fn1() == 1u). However, since the function only returns 0 or 1, you can also cast its result to boolean type and that would be fine too: if ((bool)fn()). The best solution is however to rewrite the function to return bool, after which you can use if(fn1()).

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.

Is there a MISRA-compliant way to use enum flags in C99?

I have a project I'm developing in C99 and I'm trying to make it compliant with the MISRA 2012 standard.
In one file I define an enum where each value should be treated as a flag:
/**
* Enumerates the configurable options for performing calibration.
*/
typedef enum
{
CALIBRATION_DEFAULT_OPTIONS=0, /**< Calibrate with default options */
CALIBRATION_RESET_POSITION=1, /**< Ensure window is fully open and motor re-homed */
CALIBRATION_FORCE_RECALIBRATE=2 /**< Force recalibration even if calibration data exists */
} CALIBRATION_OPTIONS_T;
I'd like to be able to declare something like:
CALIBRATION_OPTIONS_T options = CALIBRATION_RESET_POSITION | CALIBRATION_FORCE_RECALIBRATE;
I also define one function that accepts a CALIBRATION_OPTIONS_T parameter and performs different logic depending on which flags are set:
// If forced to recalibrate, do so regardless of whether metrics exist in
// EEPROM or not.
if ((options & CALIBRATION_FORCE_RECALIBRATE) != 0U)
{
MOTION_ResetCalibrationData();
calibration = performCalibrationRoutine();
}
// Otherwise try fetching existing metrics from EEPROM. If they exist, return
// these metrics.
else if (tryFetchStoredMetrics(&calibration))
{
if ((options & CALIBRATION_RESET_POSITION) != 0U)
{
calibration.lastPosition = 0;
resetMotorPosition();
storeMetrics(calibration);
}
}
However, when I lint my project with PC-lint Plus I get the following output explaining that this code violates MISRA 2012 Rule 10.1:
if ((options & CALIBRATION_FORCE_RECALIBRATE) != 0U)
~~~~~~~ ^
*** LINT: src\c\motionCalibrator.c(645) note 9027: an enum value is not an appropriate left operand to & [MISRA 2012 Rule 10.1, required]
if ((options & CALIBRATION_FORCE_RECALIBRATE) != 0U)
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*** LINT: src\c\motionCalibrator.c(645) note 9027: an enum value is not an appropriate right operand to & [MISRA 2012 Rule 10.1, required]
if ((options & CALIBRATION_FORCE_RECALIBRATE) != 0U)
^
*** LINT: src\c\motionCalibrator.c(645) warning 641: implicit conversion of enum 'CALIBRATION_OPTIONS_T' to integral type 'unsigned int'
if ((options & CALIBRATION_RESET_POSITION) != 0U)
~~~~~~~ ^
*** LINT: src\c\motionCalibrator.c(655) note 9027: an enum value is not an appropriate left operand to & [MISRA 2012 Rule 10.1, required]
if ((options & CALIBRATION_RESET_POSITION) != 0U)
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
*** LINT: src\c\motionCalibrator.c(655) note 9027: an enum value is not an appropriate right operand to & [MISRA 2012 Rule 10.1, required]
if ((options & CALIBRATION_RESET_POSITION) != 0U)
^
*** LINT: src\c\motionCalibrator.c(655) warning 641: implicit conversion of enum 'CALIBRATION_OPTIONS_T' to integral type 'unsigned int'
In particular, the MISRA 2012 standard advises against using & with enums for these two reasons:
An operand of essentially enum type should not be used in an
arithmetic operation because an enum object uses an
implementation-defined integer type. An operation involving an enum
object may therefore yield a result with an unexpected type. Note that
an enumeration constant from an anonymous enum has essentially signed
type.
Shift and bitwise operations should only be performed on operands of
essentially unsigned type. The numeric value resulting from their use
on essentially signed types is implementation-defined.
I'd like to know if there's a MISRA-compliant way I can use flag-like enums and test that specific flags are set.
This boils down to the essential type model and rule 10.1. You are only allowed to do bitwise operations on types that are essentially unsigned. Enums are treated as their own unique type by MISRA-C.
Doing things like CALIBRATION_OPTIONS_T options = CALIBRATION_RESET_POSITION | CALIBRATION_FORCE_RECALIBRATE; is otherwise fine and pretty canonical C, but you have to resort to using unsigned constants. To take type safety a bit to the extreme, you could do this:
typedef uint32_t CALIBRATION_OPTIONS_T;
#define CALIBRATION_DEFAULT_OPTIONS ((CALIBRATION_OPTIONS_T)0x00u) /**< Calibrate with default options */
#define CALIBRATION_RESET_POSITION ((CALIBRATION_OPTIONS_T)0x01u) /**< Ensure window is fully open and motor re-homed */
#define CALIBRATION_FORCE_RECALIBRATE ((CALIBRATION_OPTIONS_T)0x02u) /**< Force recalibration even if calibration data exists */
where the hex notation is self-documentating code showing that these are bit masks, the u suffix is required by MISRA in some circumstances and the uint32_t is there to block potential implicit type promotions.
Please note that using enums don't necessarily give increased type safety, but rather the opposite. They are in many cases treated like plain int, in other cases as implementation-defined size integers. Their type safety is pretty much broken by C language design. though you can make them safe with some tricks, see my posts at How to create type safe enums?.

Misra violation 12.6

How to get rid of MISRA violation on following statement
typedef unsigned char boolean;
boolean A, B;
A = !B;
Operand of logical ! operator is not an 'effectively Boolean'
expression. MISRA-C:2004 Rule 12.6; REFERENCE - ISO:C90-6.3.3.3 Unary
Arithmetic Operators
If you read rule 12.6 it says "check Boolean Expressions" in the appendix. There we can read
"Boolean-by-enforcement values can be introduced by implementing a specific type enforcement mechanism using a tool. A Boolean type could be associated with a specific typedef, and would
then be used for any objects that are Boolean. This could bring many
benefts, especially if the checking tool can support it, and in
particular it could help avoid confusion between logical operations
and integer operations."
MISRA-C:2004 assumes C90, and in C90 there is no bool type, you have to typedef it yourself, like you have done. Since your intention is to have a type which is effectively boolean, the code is just fine. In fact, your code follows MISRA recommendations beyond the mandatory ones.
The problem lies with your tool: it either does not support to allow a specific boolean type as per MISRA recommendations, or it is misconfigured.
Simple... don't use ! on things that aren't booleans. Just because your typedef is named boolean doesn't mean it is; it's still an unsigned char.
You could write:
if (b == 0) A = 1;
else A = 0;
I don't think MISRA allows ternary operators (could be wrong; not an expert) but if it does, you could write:
A = (b == 0) ? 1 : 0;
How about this:
A = (B == 0 ? 1 : 0);
Have you tried the idiom !! to convert values in boolean:
bool bool_val = !!int_val;
Then the far-fetched following code might work:
A = !(!!B) // B is "cast" within the parenthesis then we apply the "NOT"
Though the ISO:C90 standard says the operand can be of any scalar type the ! operator always yield a value of either 0 or 1; the underlying type (in MISRA-C:2004 terms) is considered effectively boolean, but the operand is not. Since the operator interprets its operand in a Boolean sense by comparing it 0 with try:
A = (B==0);
which make the logical comparison explicit. Also, depending on the tool, there may a boolean type enforcement mechanism you can configure for this typedef.

Resources