5

I have a this type structure in example.h file like this:

typedef union{
uint16_t valNum;
struct{
uint8_t valNumH;
uint8_t valNumL;
};
} valueExp;

And I am using this structure in example.c file:

uint16_t myFunction(uint16_t tempData){
uint8_t myData[8];
ValueExp mainValue;
mainValue.valNum=tempData;
myData[5]=mainValue.valNumH;

}

When I analyse IAR-CSTAT analyse this function I get this error:

Union mainValue is written as valNum then read as another field - UNION-type punning

How can I solve this message ?

hobik
  • 439
  • 4
  • 15
  • 1
    What error? Union type punning is allowed in C. Is this part of MISRA-C compliance or similar? (I think CSTAT is their MISRA checker?) – Lundin Oct 05 '20 at 08:09
  • The user manual of C-Stat states that "Writing to one field of a union and then silently reading from another field circumvents the type system. To reinterpret bit patterns deliberately, use an explicit cast." I don't really understand what issue it adresses. perhaps when both union fields have different length ? – Guillaume Petitjean Oct 05 '20 at 09:55
  • @GuillaumePetitjean *To reinterpret bit patterns deliberately, use an explicit cast* A few years late here, but throw that thing in the garbage - that's explicitly advocating UB by violating strict aliasing. – Andrew Henle Jul 24 '23 at 16:15
  • @Lundin I think you might want to address the new answer... – Andrew Henle Jul 24 '23 at 16:25
  • I note that this question is not tagged with `misra` - nor is a MISRA rule cited by the checker? – Andrew Jul 30 '23 at 13:17

1 Answers1

4

Working with Static Code Analyzers in C will render a coding standard (a "safe" C Language subset) on the top of a particular compiler implementation. It helps prevent unsafe constructs, as well as undefined behavior whenever an embedded application has safety certification burden. Using it results in a trade-off between the range of possibilities the C Language spec provides versus the stricter rules that stems from the requirements.

According to the IAR C-STAT documentation, the UNION-type-punning is a cross-check covering rules from multiple standards and it is enabled by default. For example, the CERT EXP39-C explanation:

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called “type punning”). This might be a trap representation.

The full warning message generated by the presented snippet looks like:

"main.c",18 Severity-Medium[UNION-type-punning]:Union 'mainValue' is written as 'valNum', then read as another field.
    "main.c",17: ! - Write to union field: mainValue.valNum = tempData
    "main.c",18: ! - Read from union field: mainValue.valNumH

The myFunction() requires 8-bit access. It could be rewritten in the following way to become compliant to the UNION-type-punning rule:

uint16_t myFunction(uint16_t tempData) {
  uint8_t myData[8];
  valueExp mainValue;
  mainValue.valNumH=((tempData & 0xFF00U) >> 8);
  mainValue.valNumL=(tempData & 0x00FFU);
  myData[5]=mainValue.valNumH;
/* .... */

One workaround is to suppress this check for the affected line, where valNumH is read in myFunction():

uint16_t myFunction(uint16_t tempData) {
  uint8_t myData[8];
  valueExp mainValue;
  mainValue.valNum=tempData;
#pragma cstat_suppress="UNION-type-punning"
  myData[5]=mainValue.valNumH;
/* ... */
sharpgeek
  • 481
  • 2
  • 14
  • 2
    Type-punning through a union is **NOT** undefined behavior and it is **NOT** "accessing a variable through a pointer of an incompatible type". Per [footnote 95 of the (draft) C11 standard](https://port70.net/~nsz/c/c11/n1570.html#note95): "If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6" – Andrew Henle Jul 24 '23 at 16:21
  • 1
    Not only that, the recommendation "To reinterpret bit patterns deliberately, use an explicit cast." **IS** undefined behavior as it violates strict aliasing. – Andrew Henle Jul 24 '23 at 16:22
  • See [**Type punning and Unions in C**](https://stackoverflow.com/questions/11442708/type-punning-and-unions-in-c) among many others. – Andrew Henle Jul 24 '23 at 16:24
  • Thanks for pointing it out. Reference fixed in accordance to 6.2.6, which also better matches with the C-STAT warning itself. – sharpgeek Jul 24 '23 at 21:36
  • 1
    More importantly, MISRA C allows union type punning when the purpose is to access the same data through different types, for the purpose of creating register maps, data protocols etc. It only disallows unions when using the same chunk of memory for unrelated purposes: creating "variants" and similar. – Lundin Jul 25 '23 at 16:06
  • 1
    @Lundin. Good point. Since [`UNION-type-punning`](https://netstorage.iar.com/FileStore/STANDARD/001/001/665/arm/doc/EW_CSTATGuide.ENU.pdf#page=383) allegedly addresses more than just MISRA C:2004 12.12, I decided to simply leave it out of my proposed answer. – sharpgeek Jul 25 '23 at 16:42
  • 1
    If I remember correctly MISRA C:2012 is more relaxed about unions than 2004. The rule 19.2 in 2012 is advisory. – Lundin Jul 25 '23 at 17:43