blob: a928b8aee67d9e8feeb5af77e29ade3aa383e040 [file] [log] [blame]
Hugues de Valon0f4525a2019-03-20 16:26:57 +00001################################################
2Fixing implicit casting for C enumeration values
3################################################
4
Anton Komlev19b90712021-10-19 16:28:02 +01005:Author: Hugues de Valon
Hugues de Valon0f4525a2019-03-20 16:26:57 +00006:Organization: Arm Limited
Hugues de Valon0f4525a2019-03-20 16:26:57 +00007
8********
9Abstract
10********
11
12C enumerations provide a nice way to increase readability by creating new
13enumerated types but the developer should take extra care when mixing
14enumeration and integer values.
15This document investigates C enumerations safety and proposes strategies on how
16to fix the implicit casting of the enumeration values of TF-M with other types.
17
18**************************
19C99 Standard point of view
20**************************
21
22In TF-M many implicit casts are done between integer types (``uint32_t``,
23``int32_t``, ``size_t``, etc), enumerated types (``enum foobar``) and
24enumeration constants (``FOOBAR_ENUM_1``).
25
26According to the C99 standard [1]_:
27
28 **§6.2.5, 16**:
29 An enumeration comprises a set of named integer constant values. Each
30 distinct enumeration constitutes a different numerated type.
31
32 **§6.7.2.2, 2**:
33 The expression that defines the value of an enumeration constant shall be an
34 integer constant expression that has a value representable as an int.
35
36 **§6.7.2.2, 3**:
37 The identifiers in an enumerator list are declared as constants that have
38 type int and may appear wherever such are permitted.
39
40 **§6.7.2.2, 4**:
41 Each enumerated type shall be compatible with char, a signed integer type,
42 or an unsigned integer type. The choice of type is implementation-defined,
43 but shall be capable of representing the values of all the members of the
44 enumeration.
45
46From these four quotes from the C99 standard [1]_, the following conclusions can
47be made:
48
49* an enumeration defines a new type and should be treated as such
50* the enumeration constants must only contains value representable as an ``int``
51* the enumeration constants have type ``int``
52* the actual type of the enumeration can be between ``char``, signed and
53 unsigned ``int``. The compiler chooses the type it wants among those that can
54 represent all declared constants of the enumeration.
55
56Example::
57
58 enum french_cities {
59 MARSEILLE,
60 PARIS,
61 LILLE,
62 LYON
63 };
64
65In that example, ``MARSEILLE``, ``PARIS``, ``LILLE`` and ``LYON`` are
66enumeration constants of type ``int`` and ``enum french_cities`` is a enumerated
67type which can be of actual type ``char``, ``unsigned int`` or ``int``
68(the compiler chooses!).
69
70For these reasons, doing an implicit cast between an enumeration and another
71type is the same as doing an implicit cast between two different types. From a
72defensive programming point of view, it should be checked that the destination
73type can represent the values from the origin type. In this specific case it
74means four things for enumerations:
75
76* it is always safe to assign an enumeration constant to an int, but might be
77 better to cast to show intent.
78* when casting an enumeration constant to another type, it should be checked
79 that the constant can fit into the destination type.
80* when casting from an integer type (``uint32_t``, ``int32_t``, etc) to an
81 enumeration type, it should be checked that the integer's value is one of the
82 enumeration constants. The comparison needs to be done on the biggest type of
83 the two so that no information is lost. C integer promotion should
84 automatically do that for the programmer (check §6.3.1.8, 1 for the rules).
85* when casting from an enumeration type to an integer type, it should be checked
86 that the enumeration type value fits into the integer type. The value of a
87 variable which has the type of an enumeration type is not limited to the
88 enumeration constants of the type. An enumeration constant will always fit
89 into an ``int``.
90
91*****************
92Strategies to fix
93*****************
94
950. Replace the enumerated type with an integer type and replace the enumeration
96 constant with preprocessor constants.
971. Whenever possible, try to use matching types to avoid implicit casting.
98 It happens, for example, for arithmetic operations, function calls and
99 function returns. This strategy always have the lowest performance impact.
1002. When using an enumeration constant in an arithmetic operation with another
101 type, verify that the constant can fit in the other type and cast it.
1023. When converting an integer to an enumeration type, use a conversion function
103 to check if the integer matches an enumeration constant. To not impact
104 performance too much, this function should be an inline function. If it does
105 not match, use (or add) the error constant or return an error value.
1064. When converting an enumeration type to an integer, use a conversion function
107 to check that the integer type can contain the enumeration value.
108
109************************
110Design proposal for TF-M
111************************
112
113In TF-M, an action will be taken for all enumerated types and enumeration
114constants that are used for implicit casting. The goal of this proposal is to
115remove all implicit casting of enumeration values in TF-M.
116
117The following enumerated types will be removed and replaced with preprocessor
118constants (strategy 0). These enumerated types are not used in TF-M
119but only the constants they declare.
120
121* ``enum spm_part_state_t``
122* ``enum spm_part_flag_mask_t``
123* ``enum tfm_partition_priority``
124
125The following enumerated types will be kept because they are used in the
126prototypes of functions and are useful for debugging. Whenever possible,
127strategy 1 will be applied to remove implicit casting related with those
128enumerations but dynamic conversions will be used if the first option would
129create too much change in the code base.
130
131* ``enum tfm_status_e``: the return type of the following functions will be
132 changed to return the ``enum tfm_status_e`` type. These functions are already
133 returning the enumeration constants, but implicitly casted to an integer type
134 like ``int32_t``.
135
Hugues de Valon0f4525a2019-03-20 16:26:57 +0000136 * ``int32_t check_address_range``
137 * ``int32_t has_access_to_region``
138 * ``int32_t tfm_core_check_sfn_parameters``
139 * ``int32_t tfm_start_partition``
140 * ``int32_t tfm_return_from_partition``
141 * ``int32_t tfm_check_sfn_req_integrity``
142 * ``int32_t tfm_core_check_sfn_req_rules``
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800143 * ``int32_t tfm_spm_sfn_request_handler``
144 * ``int32_t tfm_spm_sfn_request_thread_mode``
Hugues de Valon0f4525a2019-03-20 16:26:57 +0000145* ``enum tfm_buffer_share_region_e``: the following function prototypes will be
146 changed:
147
148 * ``tfm_spm_partition_set_share(uint32_t partition_idx, uint32_t share)`` -> ``tfm_spm_partition_set_share(uint32_t partition_idx, enum tfm_buffer_share_region_e share)``
149* ``enum tfm_memory_access_e``
150* ``enum attest_memory_access_t``
151* ``enum engine_cipher_mode_t``
152* ``mbedtls_cipher_type_t``
153
154The following enumerated types are used for error code values of Secure service
155calls. They should be kept as they are part of the interface and might be used
156by external parties in Non-Secure code. For the Initial Attestation service,
157the enumeration is defined in the PSA Attestation API specifications.
158
159* ``enum psa_attest_err_t``
160* ``enum psa_audit_err``
161* ``enum tfm_platform_err_t``
162
163Implicit casting related with these enumerations is happening in two locations
164of TF-M and need conversion functions in those locations, because the types can
165not be changed:
166
167* In the Non-Secure Client library, all of the Secure Service functions
168 implicitly cast the ``uint32_t`` returned by ``tfm_ns_lock_dispatch`` to
169 these enumerated types. Strategy 3 is needed here.
170* In all of the veneer functions, there is an implicit cast from the ``int32_t``
171 value returned by the SVC request function (``tfm_core_*_request``) to these
172 enumerated types. Strategy 3 is needed here as well. The implicit cast will
173 eventually be removed if all of the services are using the Uniform Signatures
174 Prototypes so that the veneer functions all return ``psa_status_t`` which is
175 an ``int32_t``.
176
177If the interface of those services can be changed, these enumerations could be
178removed and replaced with the ``psa_status_t`` type to remove the implicit
179casting.
180
181.. [1] C99 standard: http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
182
183
184--------------
185
186
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800187*Copyright (c) 2019-2020, Arm Limited. All rights reserved.*
Hugues de Valon0f4525a2019-03-20 16:26:57 +0000188