MISRA 10.3 issue about AUTOSAR booleans
Asked Answered
F

3

7

In my firm project, the AUTOSAR platform defines booleans like this

typedef unsigned char boolean;

plus

#ifndef TRUE 
#define TRUE 1 
#endif 
#ifndef FALSE 
#define FALSE 0 
#endif

This is not modifiable. Then we get the MISRA 10.3 error Expression assigned to a narrower or different essential type [MISRA 2012 Rule 10.3, required] on the following two assignments (real code replaced, of course!)

boolean mybool = (boolean)FALSE;
if(some_condition)
{
   mybool = (boolean)TRUE;
}

We've tried other convertions with (uint8)FALSE or (unsigned char)FALSE or even without a convertion mybool = TRUE; without curing the issue. We would be happy to avoid justifying for deviation.

Does anyone has an idea of what happens and how to cure it?


@Fredrik Thanks for your first answer. I put this in a dummy header, included it in the 'culprit' .c and run PC-Lint/MISRA on this unit

#define testTRUE 1U
boolean x = testTRUE;
boolean y = (uint8)testTRUE;
boolean z = (boolean)testTRUE;

#define testTRUE_2 1
boolean x_2 = testTRUE_2;
boolean y_2 = (uint8)testTRUE_2;
boolean z_2 = (boolean)testTRUE_2;

unsigned char x_3 = (boolean)1;
unsigned char y_3 = (boolean)testTRUE;
unsigned char z_3 = (boolean)testTRUE_2;

and get the same issue on the first 6 assignments. As to last 3 assignments, the error is not raised but perhaps hidden by this one in replacement: Use of modifier or type 'unsigned' outside of a typedef [MISRA 2012 Directive 4.6, advisory]

Frigging answered 25/11, 2020 at 18:34 Comment(6)
Out of curiosity, for OP and others in the same situation: what is the rationale behind using custom boolean values over the standard bool (or, at the very least, _Bool)? Sticking with C89?Hearsay
@Hearsay My guess is that they can't use the standard library, and considering they are using MISRA I guess that it is so.Relevant
@Relevant My point was that _Bool is provided by the C99 language (supported by MISRA 2012, used by OP) itself and does not require the Standard Library at all so, even in baremetal applications with absolutely no other code or library, it's still there. Anyway, after a bit of digging, I guess the answer to my previous question is: just ask the AUTOSAR guys as that's where OP's boolean comes from (see page 19) and they seem to be very serious about re-defining every single type ...Hearsay
@Hearsay yes you are correct about _Bool. I'm surprised AUTOSAR could get the literals for true and false wrong..Relevant
@Frigging to be honest, if you still get the warning then I have no clue.. :/Relevant
@PiCTo: Keep in mind, that AUTOSAR still allows for compatability to C90, and not just C99 or C11. Also keep in mind that AUTOSAR considers _Bool mapped to BIT types (e.g. '_bit' in some implementations) , which you might not be able to pass per pointer to in APIs. And using TRUE and FALSEis just conform to common automotive naming conventions for MACROS and DEFINES as uppercase.Opsonin
W
2

The thing with MISRA-C and booleans is that MISRA encourage us to "pretend" that there is a boolean type in the language and treat for example the result from relational and equality operators as "essentially boolean".

That is, treat the boolean type as C++ would. C did introduce booleans in C99, but the result of the mentioned operators is still int, not bool like in C++. But MISRA wants us to "pretend" that they are bool, to get the code right. In addition, MISRA-C still covers C90 where there is no standard bool/true/false to be had.

So in order to get booleans to work like MISRA wants them, you need a way to tell your static analyser that boolean, TRUE and FALSE is your boolean type. Otherwise the tool will treat them as int and then you get all manner of implicit conversion warnings. I don't know how to do that on PC-Lint, but the error is a tool configuration issue.

As for the code posted, boolean mybool = FALSE; is MISRA compliant, given that this is the "essentially boolean" type. No need to cast. And if you didn't configure the tool, no casting will save you. In general, never cast in C unless you know why you are doing it.

Willywilly answered 30/11, 2020 at 7:46 Comment(4)
You are right. That is why the best workaround is to define boolean as an enum, and TRUE and FALSE as values of that enum. That minimizes the chances of type mismatches and type conversions.Agnusago
@Agnusago No, that is wrong. You should preferably use C99 bool if C99 is available. In either case the static analyser needs to treat boolean types as a special type category, in order to give correct diagnostics for MISRA-C:2012.Willywilly
My comment was based on your statement: "MISRA-C still covers C90" - which excludes the availability of C99, at least from the MISRA point of view. Of course, having a proper "boolean" type (whatever it is called) is the preferred situation.Agnusago
@Agnusago The released MISRA C covers both C90 and C99, if C99 is in use, the rules apply with its features in mind. It absolutely does not exclude the use of C99-only features.Effy
G
2

This is not modifiable.

I understand that AUTOSAR has some strange type requirements, that pre-date C11. Users of AUTOSAR have to live with that (and suggestions of how to get around them don't help)

Then we get the MISRA 10.3 error Expression assigned to a narrower or different essential type [MISRA 2012 Rule 10.3, required] on the following two assignments (real code replaced, of course!)

I think, at the heart of this is the apparent conflict between unsigned char and 0/1 (which are signed)... but this is addressed by Exception 1 of Rule 10.3 so not a violation.

But within the examples in the book there is:

bool_t bla = 0 /* Non-compliant: boolean and signed */

This implies that Exception 1 doesn't apply for booleans, which is curious!

Notwithstanding the use of the custom boolean type rather than standard _Bool or bool, I suspect this may be a tool configuration issue... you need to tell PCLINT that the custom boolean type (and TRUE/FALSE) is your essentially boolean type

Or failing that (ie if PCLINT doesn't have such a capability), you may need to deviate Rule 10.3

Disclaimer: See Profile!


UPDATE: I raised this question at a MISRA C WG (virtual) meeting. The agreement of the WG is that this is a false-positive, and that the Tool should be configured to cope with this - AUTOSAR users in the WG reported their configuration (albeit not using PCLINT) correctly did not flag this.

Gur answered 23/12, 2020 at 16:38 Comment(0)
A
1

On occasion, static analysis tools have bugs - I have run into this kind of problem a few times. You might have hit one of them. It is the best if you contact the provider of the tool and ask for their opinion on the error, as well as how to fix it - either the code, or the tool. Just explain them what you explained us here.


To my knowledge, AUTOSAR is driven a lot by politics, and "science" is secondary. Therefore, many unusual or unexpected things can be found there.

I do not have a static analysis tool of any kind at the moment, so I cannot test it. But I think that the most correct way to define TRUE and FALSE in the context would be:

#ifndef TRUE 
#define TRUE ((boolean)(1==1))
#endif 
#ifndef FALSE 
#define FALSE ((boolean)(1==0))
#endif

This overcomes 2 issues with the original definition:

  1. Compilers are allowed to define their internal TRUE and FALSE values to any values. While FALSE is usually (always?) 0, TRUE might actually have any non-zero value.

  2. With the new definition, the TRUE and FALSE actually have the boolean type.


The most recommended definition would be:

typedef enum boolean_tag
{
    FALSE,
    TRUE
} boolean;

which would make any other value completely illegal.

I am not sure if the following would work:

typedef enum boolean_tag
{
    FALSE = (1==0),
    TRUE = (1==1)
} boolean;

Comment (might not be applicable to your current situation):

Statements like

if ( boolean_variable )
{
    /* do_smth */
}

are not a best practice. If I remember correctly there was even a MISRA rule to use

if (boolean_variable == TRUE)
{
    /* do_smth */
}

instead - exactly in order to avoid conflicts with the inner workings of the compiler.

Agnusago answered 30/11, 2020 at 8:16 Comment(5)
Unfortunately, we may not deviate from the AUTOSAR definition of booleans, TRUE and FALSE. They are generated by AUTOSAR build tools which comply to the norm.Frigging
"Compilers are allowed to define their internal TRUE and FALSE values to any values." No, this is wrong. The C standard has well-defined results for relational, equality, not operators, since the dawn of time. "TRUE" is always 1 which is of type int and "FALSE" is always 0 and of type int. This is compatible with C99 stdbool.h. However, that's not how booleans work in MISRA-C, as explained in the answer I posted.Willywilly
In addition, stuff like #define TRUE ((boolean)(1==1)) is completely nonsensical. It is the same thing as (boolean)1 and the equality operator adds absolutely nothing. Also, if boolean happens to be an enum the cast achieves absolutely nothing either. This answer is full of misconceptions and factual errors.Willywilly
if ( boolean_variable ) is MISRA compliant and it is fine practice since the variable is essentially boolean. boolean_variable == TRUE is also MISRA compliant but not necessary to achieve MISRA compliance.Willywilly
Furthermore, in case the actual standard type bool/_Bool is used, then a cast from a non-zero value such as (bool)5 results in 1, which is a special attribute of the built-in boolean type in C. Unlike (some_enum)5 which results in 5.Willywilly

© 2022 - 2024 — McMap. All rights reserved.