The vulnerability documented in ISO IEC 24772-1 clause 6.5 applies to C++, as C++ allows the specification of the values underlying the enumerators.
C++ provides scoped (enum class
) and unscoped (enum
) enumeration types, where an underlying integral type can be specified. Unscoped enumeration types without an enum-base have a non-fixed underlying type that only guarantees values in the range of the provided enumerators are valid. The latter can cause non-representable values to be assigned to a variable of such an unscoped enumeration type. For enumeration types with a fixed underlying type all values of the underlying integral type are valid. See ISO IEC 24772-3 for vulnerabilities associated with unscoped enums with no fixed underlying type, except an explicit conversion is required to convert an integer to an enumeration type object.
Casting a value to an enumeration type is undefined behavior [EWF] unless the source value is within the range of values of an enumeration type. See CERT INT50-CPP. (remove CERT reference???)
enum Color {red=1, green, blue};
short i = red; // implicit conversion
// Undefined-defined behaviour since 5 will not fit into
Color g { Color(green + blue) }; // the smallest bitfield to hold red, green and blue
C++ does not support implicit conversion of a scoped enum to other types, hence, operations (such as arithmetic operations) must be explicitly provided.
In the following example, based upon the above definition,
void foo () {
// well-formed for unscoped enum, ill-formed for scoped enum.
i + red ; }
Scoped enums, on the other hand, require that the conversions to/from the enumeration type must be explicit, as shown below:
enum class Color : short { red, green, blue };
short i = static_cast<short>(Color::red);
operator+(Color a, short b)
Color
{return static_cast<Color>((static_cast<short>(a) + b) % 3);
}
Unscoped enumeration types implicitly promote to an integral type and can be used as the index of an array without a cast. Without a user-specified mapping to an underlying representation, there will be “holes” as documented in ISO IEC 24772-1:2024 clause 6.5 and ISO IEC TR 24772-3 clause 6.5.
To avoid the vulnerability or mitigate its ill effects, C++ software developers can:
Prefer scoped enumerations with an explicit fixed underlying type.
See CPP Core Guidelines Enum.3 "Prefer class enums over 'plain'
enums".
See AUTOSAR A7-2-3 "Enumerations shall be declared as scoped
enum classes"
See MISRA C++ 8.5.3
See MISRA C++ 28.5.5
If unscoped enumerations are used, follow the general advice of TR 24772-3 clause 6.5.2 as well as the following:
For an enumeration type with a fixed underlying type, avoid assigning integer values that are outside the range of the enumeration’s underlying type.
For an enumeration type with no fixed underlying type, avoid assigning integer values that cannot be represented by the enumeration type.
Avoid casting integer values to enumeration type values, but if unavoidable, ensure that it corresponds to a named enumerator.