Start here

Home
About Klocwork
What's new
Fixed issues
Release notes
Installation

Reference

C/C++ checkers
Java checkers
C# checkers
MISRA C 2004 checkers
MISRA C++ 2008 checkers
MISRA C 2012 checkers
MISRA C 2012 checkers with Amendment 1
Commands
Metrics
Troubleshooting
Reference

Product components

C/C++ Integration build analysis
Java Integration build analysis
Desktop analysis
Refactoring
Klocwork Static Code Analysis
Klocwork Code Review
Structure101
Tuning
Custom checkers

Coding environments

Visual Studio
Eclipse for C/C++
Eclipse for Java
IntelliJ IDEA
Other

Administration

Project configuration
Build configuration
Administration
Analysis performance
Server performance
Security/permissions
Licensing
Klocwork Static Code Analysis Web API
Klocwork Code Review Web API

Community

View help online
Visit RogueWave.com
Klocwork Support
Rogue Wave Videos

Legal

Legal information

MISRA.UNION

Union is used.

MISRA C 2012 Rule 19.2 The union keyword should not be used

C90 [Undefined 39, 40; Implementation 27], C99 [Unspecified 10; Undefined 61, 62]

Category: Advisory

Analysis: Decidable, Single Translation Unit

Applies to: C90, C99

Rationale

A union member can be written and the same member can then be read back in a well-defined manner.

However, if a union member is written and then a different union member is read back, the behaviour depends on the relative sizes of the members:
  • If the member read is wider than the member written then the value is unspecified;
  • Otherwise, the value is implementation-defined.

The Standard permits the bytes of a union member to be accessed by means of another member whose type is array of unsigned char. However, since it is possible to access bytes with unspecified values, unions should not be used.

If this rule is not followed, the kinds of behaviour that need to be determined are:

  • Padding — how much padding is inserted at the end of the union;
  • Alignment — how are members of any structures within the union aligned;
  • Endianness — is the most significant byte of a word stored at the lowest or highest memory address;
  • Bit-order — how are bits numbered within bytes and how are bits allocated to bit fields.

Example

In this non-compliant example, a 16-bit value is stored into a union but a 32-bit value is read back resulting in an unspecified value being returned.

uint32_t zext ( uint16_t s ) 
{
  union 
  {
    uint32_t ul; 
    uint16_t us; 
  } tmp;

  tmp.us = s; 
  return tmp.ul; /* unspecified value */ 
}

See also

Rule 19.1

MISRA-C 2004 Rule 18.4 (required): Unions shall not be used.

Union is used.

[Implementation 27]

Rule 18.3 prohibits the reuse of memory areas for unrelated purposes. However, even when memory is being reused for related purposes, there is still a risk that the data may be misinterpreted. Therefore, this rule prohibits the use of unions for any purpose.

It is recognised nonetheless that there are situations in which the careful use of unions is desirable in constructing an efficient implementation. In such situations, deviations to this rule are considered acceptable provided that all relevant implementation-defined behaviour is documented. This might be achieved in practice by referencing the implementation section of the compiler manuals from the design documentation. The kinds of implementation behaviour that might be relevant are:

  • padding — how much padding is inserted at the end of the union
  • alignment — how are members of any structures within the union aligned
  • endianness — is the most significant byte of a word stored at the lowest or highest memory address
  • bit-order — how are bits numbered within bytes and how are bits allocated to bit fields

The use of deviations is acceptable for (a) packing and unpacking of data, for example when sending and receiving messages, and (b) implementing variant records provided that the variants are differentiated by a common field. Variant records without a differentiator are not considered suitable for use in any situation.

Packing and unpacking data

In this example, a union is used to access the bytes of a 32-bit word in order to store bytes received over a network most-significant byte first. The assumptions that this particular implementation rely on are:

  • the uint32_t type occupies 32 bits
  • the uint8_t type occupies 8 bits
  • the implementation stores words with the most significant byte at the lowest memory address

The code to implement the receipt and packing of the bytes could be:

typedef union {
   uint32_t word;
   uint8_t bytes[4];
} word_msg_t;

uint32_t read_word_big_endian (void)

{
   word_msg_t tmp;

   tmp.bytes[0] = read_byte();
   tmp.bytes[1] = read_byte();
   tmp.bytes[2] = read_byte();
   tmp.bytes[3] = read_byte();

   return (tmp.word);
}

It is worth noting that the body of the routine could be written in a portable manner as follows:

uint32_t read_word_big_endian (void)
{
   uint32_t word;

   word =         ((uint32_t)read_byte()) << 24;
   word = word | (((uint32_t)read_byte()) << 16);
   word = word | (((uint32_t)read_byte()) << 8);
   word = word |  ((uint32_t)read_byte());

   return (word);
}

Unfortunately, most compilers produce far less efficient code when faced with the portable implementation. When high execution speed or low program memory usage is more important than portability, the implementation using unions might be preferred.

Variant records

Unions are often used to implement variant records. Each variant shares common fields and has additional fields that are specific to the variant. This example is based on the CAN Calibration Protocol (CCP), in which each CAN message sent to a CCP client shares two common fields, each of one byte. Up to 6 additional bytes may follow, the interpretation of which depends on the message type stored in the first byte.

The assumptions that this particular implementation rely on are:

  • the uint16_t type occupies 16 bits
  • the uint8_t type occupies 8 bits
  • the alignment and packing rules are such that there is no gap between the uint8_t and uint16_t members of the structure

In the interests of brevity, only two message types are considered in this example. The code that is presented here is incomplete and should be viewed merely to illustrate the purpose of variant records and not as a model implementation of CCP.

/* The fields common to all CCP messages */
typedef struct {
   uint8_t msg_type;
   uint8_t sequence_no;
} ccp_common_t;

/* CCP connect message */
typedef struct {
   ccp_common_t common_part;
   uint16_t station_to_connect;
} ccp_connect_t;

/* CCP disconnect message */
typedef struct {
   ccp_common_t common_part;
   uint8_t disconnect_command;
   uint8_t pad;
   uint16_t station_to_disconnect;
} ccp_disconnect_t;

/* The variant */
typedef union {
   ccp_common_t common;
   ccp_connect_t connect;
   ccp_disconnect_t disconnect;
} ccp_message_t;

void process_ccp_message (ccp_message_t *msg)
{
   switch (msg->common.msg_type)
   {
   case Ccp_connect:
      if (MY_STATION == msg->connect.station_to_connect)
      {
         ccp_connect ();
      }
      break;

   case Ccp_disconnect:
      if (MY_STATION == msg->disconnect.station_to_disconnect)
      {
         if (PERM_DISCONNECT == msg->disconnect.disconnect_command)
         {
            ccp_disconnect ();
         }
      }
      break;

   default:
      break; /* ignore unknown commands */
   }
}

MISRA-C++ 2008 Rule 9—5—1 (required): Unions shall not be used

This rule is also covered by MISRA.ASSIGN.OVERLAP.

[Implementation 3.9(4, 5)]

Rationale

The use of unions to access an object in different ways may result in the data being misinterpreted.

Therefore, this rule prohibits the use of unions for any purpose.

It is recognized nonetheless that there are situations in which the careful use of unions is desirable in constructing an efficient implementation. In such situations, deviations to this rule are considered acceptable provided that all relevant implementation-defined behaviour is documented. This might be achieved in practice by referencing the implementation section of the compiler manuals from the design documentation.

Example

namespace NS1
{
               // Compliant - no union
}
namespace NS2
{
   union U1    // Non-compliant — union
   {
      int32_t i;
      float32_t j;
   };
}