The vulnerability documented in ISO IEC 24772-1 clause 6.5 applies to C++. C++ provides scoped (enum class
) and unscoped (enum
) enumeration types, where an underlying integral type can be specified. For enumeration types with a fixed underlying type all values of the underlying integral type are valid. 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.
Assignment of a variable of an enum type require the assigned value to be of the same enum type. This can be either an enumerator of that enum type, or requires a cast (see 6.6 Conversion errors [FLC]).
C++ allows implicit conversion of an unscoped enum by integral promotion.
TODO continue here
enum Color {red, green, blue};
short i = red; // implicit conversion
// integer result fits into short
Color g { green + blue }; 42}; // OK non-narrowing Color h {
List initialization of enum types with fixed underlying type implicitly does a static cast.
C++ does not support implicit conversion of a scoped enum to an int, hence, operations such as ++
, +
, <
and enums used as array indices require explicit definitions.
enum class Color : short {red, green, blue};
short i = red; // error -- no implicit conversion
Where unscoped enums are used as array indexes and do not have a user-specified mapping to an underlying representation, there will be “holes” as documented in TR24772-1 clause 6.6.
Note that unscoped enumeration types implicitly promote their underlying type and can be used as the index of an array without a cast, with all of the issues described in TR 24772-1 clause 6.5.
From C++ 2017 forward, casting a value to an enumeration type is undefined behavior unless the source value is within the range of values of an enumeration type. See CERT INT50-CPP.
To avoid the vulnerability or mitigate its ill effects, C++ software developers can:
Use scoped enumerations in preference to the C-style unscoped enumerations for related values, especially at namespace-level.
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++ 28.5.5
Use constexpr
to declare a set of unrelated values, such as constexpr size_t bufferLen = 128;
constexpr char special_char = 'a';
Provide operators and functions that perform the arithmetic operations and conversions appropriate to the enumerated type. Outside those functions, avoid directly performing arithmetic or conversions on objects of the enumerated type.
See CPP Core Guidelines Enum.4 "Define operations on
enumerations for safe and simple use"If unscoped enumerations are used, follow the general advice of TR 24772-3 clause 6.5.2 as well as the following:
Avoid casting arbitrary integer values to enumeration type. If it is
unavoidable, use braced initialization instead of C-style or static casts
e_type{7};
> See CERT INT50-CPP "Do no Cast to an out-of-range-value"
Obtain the underlying enumeration value, by casting the enumeration
to its underlying type, e.g.,
enum e_type{A, B, C};
auto value = static_cast\<std::underlying_type_t\<e_type\>\>(B);