LCOV - code coverage report
Current view: top level - os_stub/mbedtlslib/mbedtls/library - common.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 50.0 % 14 7
Test Date: 2025-06-29 08:09:00 Functions: - 0 0

            Line data    Source code
       1              : /**
       2              :  * \file common.h
       3              :  *
       4              :  * \brief Utility macros for internal use in the library
       5              :  */
       6              : /*
       7              :  *  Copyright The Mbed TLS Contributors
       8              :  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       9              :  */
      10              : 
      11              : #ifndef MBEDTLS_LIBRARY_COMMON_H
      12              : #define MBEDTLS_LIBRARY_COMMON_H
      13              : 
      14              : #include "mbedtls/build_info.h"
      15              : #include "alignment.h"
      16              : 
      17              : #include <assert.h>
      18              : #include <stddef.h>
      19              : #include <stdint.h>
      20              : #include <stddef.h>
      21              : 
      22              : #if defined(__ARM_NEON)
      23              : #include <arm_neon.h>
      24              : #define MBEDTLS_HAVE_NEON_INTRINSICS
      25              : #elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
      26              : #include <arm64_neon.h>
      27              : #define MBEDTLS_HAVE_NEON_INTRINSICS
      28              : #endif
      29              : 
      30              : /** Helper to define a function as static except when building invasive tests.
      31              :  *
      32              :  * If a function is only used inside its own source file and should be
      33              :  * declared `static` to allow the compiler to optimize for code size,
      34              :  * but that function has unit tests, define it with
      35              :  * ```
      36              :  * MBEDTLS_STATIC_TESTABLE int mbedtls_foo(...) { ... }
      37              :  * ```
      38              :  * and declare it in a header in the `library/` directory with
      39              :  * ```
      40              :  * #if defined(MBEDTLS_TEST_HOOKS)
      41              :  * int mbedtls_foo(...);
      42              :  * #endif
      43              :  * ```
      44              :  */
      45              : #if defined(MBEDTLS_TEST_HOOKS)
      46              : #define MBEDTLS_STATIC_TESTABLE
      47              : #else
      48              : #define MBEDTLS_STATIC_TESTABLE static
      49              : #endif
      50              : 
      51              : #if defined(MBEDTLS_TEST_HOOKS)
      52              : extern void (*mbedtls_test_hook_test_fail)(const char *test, int line, const char *file);
      53              : #define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST) \
      54              :     do { \
      55              :         if ((!(TEST)) && ((*mbedtls_test_hook_test_fail) != NULL)) \
      56              :         { \
      57              :             (*mbedtls_test_hook_test_fail)( #TEST, __LINE__, __FILE__); \
      58              :         } \
      59              :     } while (0)
      60              : #else
      61              : #define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST)
      62              : #endif /* defined(MBEDTLS_TEST_HOOKS) */
      63              : 
      64              : /** \def ARRAY_LENGTH
      65              :  * Return the number of elements of a static or stack array.
      66              :  *
      67              :  * \param array         A value of array (not pointer) type.
      68              :  *
      69              :  * \return The number of elements of the array.
      70              :  */
      71              : /* A correct implementation of ARRAY_LENGTH, but which silently gives
      72              :  * a nonsensical result if called with a pointer rather than an array. */
      73              : #define ARRAY_LENGTH_UNSAFE(array)            \
      74              :     (sizeof(array) / sizeof(*(array)))
      75              : 
      76              : #if defined(__GNUC__)
      77              : /* Test if arg and &(arg)[0] have the same type. This is true if arg is
      78              :  * an array but not if it's a pointer. */
      79              : #define IS_ARRAY_NOT_POINTER(arg)                                     \
      80              :     (!__builtin_types_compatible_p(__typeof__(arg),                \
      81              :                                    __typeof__(&(arg)[0])))
      82              : /* A compile-time constant with the value 0. If `const_expr` is not a
      83              :  * compile-time constant with a nonzero value, cause a compile-time error. */
      84              : #define STATIC_ASSERT_EXPR(const_expr)                                \
      85              :     (0 && sizeof(struct { unsigned int STATIC_ASSERT : 1 - 2 * !(const_expr); }))
      86              : 
      87              : /* Return the scalar value `value` (possibly promoted). This is a compile-time
      88              :  * constant if `value` is. `condition` must be a compile-time constant.
      89              :  * If `condition` is false, arrange to cause a compile-time error. */
      90              : #define STATIC_ASSERT_THEN_RETURN(condition, value)   \
      91              :     (STATIC_ASSERT_EXPR(condition) ? 0 : (value))
      92              : 
      93              : #define ARRAY_LENGTH(array)                                           \
      94              :     (STATIC_ASSERT_THEN_RETURN(IS_ARRAY_NOT_POINTER(array),         \
      95              :                                ARRAY_LENGTH_UNSAFE(array)))
      96              : 
      97              : #else
      98              : /* If we aren't sure the compiler supports our non-standard tricks,
      99              :  * fall back to the unsafe implementation. */
     100              : #define ARRAY_LENGTH(array) ARRAY_LENGTH_UNSAFE(array)
     101              : #endif
     102              : /** Allow library to access its structs' private members.
     103              :  *
     104              :  * Although structs defined in header files are publicly available,
     105              :  * their members are private and should not be accessed by the user.
     106              :  */
     107              : #define MBEDTLS_ALLOW_PRIVATE_ACCESS
     108              : 
     109              : /**
     110              :  * \brief       Securely zeroize a buffer then free it.
     111              :  *
     112              :  *              Similar to making consecutive calls to
     113              :  *              \c mbedtls_platform_zeroize() and \c mbedtls_free(), but has
     114              :  *              code size savings, and potential for optimisation in the future.
     115              :  *
     116              :  *              Guaranteed to be a no-op if \p buf is \c NULL and \p len is 0.
     117              :  *
     118              :  * \param buf   Buffer to be zeroized then freed.
     119              :  * \param len   Length of the buffer in bytes
     120              :  */
     121              : void mbedtls_zeroize_and_free(void *buf, size_t len);
     122              : 
     123              : /** Return an offset into a buffer.
     124              :  *
     125              :  * This is just the addition of an offset to a pointer, except that this
     126              :  * function also accepts an offset of 0 into a buffer whose pointer is null.
     127              :  * (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
     128              :  * A null pointer is a valid buffer pointer when the size is 0, for example
     129              :  * as the result of `malloc(0)` on some platforms.)
     130              :  *
     131              :  * \param p     Pointer to a buffer of at least n bytes.
     132              :  *              This may be \p NULL if \p n is zero.
     133              :  * \param n     An offset in bytes.
     134              :  * \return      Pointer to offset \p n in the buffer \p p.
     135              :  *              Note that this is only a valid pointer if the size of the
     136              :  *              buffer is at least \p n + 1.
     137              :  */
     138              : static inline unsigned char *mbedtls_buffer_offset(
     139              :     unsigned char *p, size_t n)
     140              : {
     141              :     return p == NULL ? NULL : p + n;
     142              : }
     143              : 
     144              : /** Return an offset into a read-only buffer.
     145              :  *
     146              :  * Similar to mbedtls_buffer_offset(), but for const pointers.
     147              :  *
     148              :  * \param p     Pointer to a buffer of at least n bytes.
     149              :  *              This may be \p NULL if \p n is zero.
     150              :  * \param n     An offset in bytes.
     151              :  * \return      Pointer to offset \p n in the buffer \p p.
     152              :  *              Note that this is only a valid pointer if the size of the
     153              :  *              buffer is at least \p n + 1.
     154              :  */
     155              : static inline const unsigned char *mbedtls_buffer_offset_const(
     156              :     const unsigned char *p, size_t n)
     157              : {
     158              :     return p == NULL ? NULL : p + n;
     159              : }
     160              : 
     161              : /* Always inline mbedtls_xor() for similar reasons as mbedtls_xor_no_simd(). */
     162              : #if defined(__IAR_SYSTEMS_ICC__)
     163              : #pragma inline = forced
     164              : #elif defined(__GNUC__)
     165              : __attribute__((always_inline))
     166              : #endif
     167              : /**
     168              :  * Perform a fast block XOR operation, such that
     169              :  * r[i] = a[i] ^ b[i] where 0 <= i < n
     170              :  *
     171              :  * \param   r Pointer to result (buffer of at least \p n bytes). \p r
     172              :  *            may be equal to either \p a or \p b, but behaviour when
     173              :  *            it overlaps in other ways is undefined.
     174              :  * \param   a Pointer to input (buffer of at least \p n bytes)
     175              :  * \param   b Pointer to input (buffer of at least \p n bytes)
     176              :  * \param   n Number of bytes to process.
     177              :  *
     178              :  * \note      Depending on the situation, it may be faster to use either mbedtls_xor() or
     179              :  *            mbedtls_xor_no_simd() (these are functionally equivalent).
     180              :  *            If the result is used immediately after the xor operation in non-SIMD code (e.g, in
     181              :  *            AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
     182              :  *            registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
     183              :  *            the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
     184              :  *            For targets without SIMD support, they will behave the same.
     185              :  */
     186              : static inline void mbedtls_xor(unsigned char *r,
     187              :                                const unsigned char *a,
     188              :                                const unsigned char *b,
     189              :                                size_t n)
     190              : {
     191        10011 :     size_t i = 0;
     192              : #if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
     193              : #if defined(MBEDTLS_HAVE_NEON_INTRINSICS) && \
     194              :     (!(defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_GCC_VERSION < 70300))
     195              :     /* Old GCC versions generate a warning here, so disable the NEON path for these compilers */
     196              :     for (; (i + 16) <= n; i += 16) {
     197              :         uint8x16_t v1 = vld1q_u8(a + i);
     198              :         uint8x16_t v2 = vld1q_u8(b + i);
     199              :         uint8x16_t x = veorq_u8(v1, v2);
     200              :         vst1q_u8(r + i, x);
     201              :     }
     202              : #if defined(__IAR_SYSTEMS_ICC__)
     203              :     /* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
     204              :      * where n is a constant multiple of 16.
     205              :      * For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
     206              :      * constant, and is a very small perf regression if n is not a compile-time constant. */
     207              :     if (n % 16 == 0) {
     208              :         return;
     209              :     }
     210              : #endif
     211              : #elif defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
     212              :     /* This codepath probably only makes sense on architectures with 64-bit registers */
     213        34194 :     for (; (i + 8) <= n; i += 8) {
     214        48366 :         uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
     215        24183 :         mbedtls_put_unaligned_uint64(r + i, x);
     216              :     }
     217              : #if defined(__IAR_SYSTEMS_ICC__)
     218              :     if (n % 8 == 0) {
     219              :         return;
     220              :     }
     221              : #endif
     222              : #else
     223              :     for (; (i + 4) <= n; i += 4) {
     224              :         uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
     225              :         mbedtls_put_unaligned_uint32(r + i, x);
     226              :     }
     227              : #if defined(__IAR_SYSTEMS_ICC__)
     228              :     if (n % 4 == 0) {
     229              :         return;
     230              :     }
     231              : #endif
     232              : #endif
     233              : #endif
     234        15729 :     for (; i < n; i++) {
     235         5718 :         r[i] = a[i] ^ b[i];
     236              :     }
     237        10011 : }
     238              : 
     239              : /* Always inline mbedtls_xor_no_simd() as we see significant perf regressions when it does not get
     240              :  * inlined (e.g., observed about 3x perf difference in gcm_mult_largetable with gcc 7 - 12) */
     241              : #if defined(__IAR_SYSTEMS_ICC__)
     242              : #pragma inline = forced
     243              : #elif defined(__GNUC__)
     244              : __attribute__((always_inline))
     245              : #endif
     246              : /**
     247              :  * Perform a fast block XOR operation, such that
     248              :  * r[i] = a[i] ^ b[i] where 0 <= i < n
     249              :  *
     250              :  * In some situations, this can perform better than mbedtls_xor() (e.g., it's about 5%
     251              :  * better in AES-CBC).
     252              :  *
     253              :  * \param   r Pointer to result (buffer of at least \p n bytes). \p r
     254              :  *            may be equal to either \p a or \p b, but behaviour when
     255              :  *            it overlaps in other ways is undefined.
     256              :  * \param   a Pointer to input (buffer of at least \p n bytes)
     257              :  * \param   b Pointer to input (buffer of at least \p n bytes)
     258              :  * \param   n Number of bytes to process.
     259              :  *
     260              :  * \note      Depending on the situation, it may be faster to use either mbedtls_xor() or
     261              :  *            mbedtls_xor_no_simd() (these are functionally equivalent).
     262              :  *            If the result is used immediately after the xor operation in non-SIMD code (e.g, in
     263              :  *            AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
     264              :  *            registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
     265              :  *            the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
     266              :  *            For targets without SIMD support, they will behave the same.
     267              :  */
     268              : static inline void mbedtls_xor_no_simd(unsigned char *r,
     269              :                                        const unsigned char *a,
     270              :                                        const unsigned char *b,
     271              :                                        size_t n)
     272              : {
     273            0 :     size_t i = 0;
     274              : #if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
     275              : #if defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
     276              :     /* This codepath probably only makes sense on architectures with 64-bit registers */
     277            0 :     for (; (i + 8) <= n; i += 8) {
     278            0 :         uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
     279            0 :         mbedtls_put_unaligned_uint64(r + i, x);
     280              :     }
     281              : #if defined(__IAR_SYSTEMS_ICC__)
     282              :     /* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
     283              :      * where n is a constant multiple of 8.
     284              :      * For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
     285              :      * constant, and is a very small perf regression if n is not a compile-time constant. */
     286              :     if (n % 8 == 0) {
     287              :         return;
     288              :     }
     289              : #endif
     290              : #else
     291              :     for (; (i + 4) <= n; i += 4) {
     292              :         uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
     293              :         mbedtls_put_unaligned_uint32(r + i, x);
     294              :     }
     295              : #if defined(__IAR_SYSTEMS_ICC__)
     296              :     if (n % 4 == 0) {
     297              :         return;
     298              :     }
     299              : #endif
     300              : #endif
     301              : #endif
     302            0 :     for (; i < n; i++) {
     303            0 :         r[i] = a[i] ^ b[i];
     304              :     }
     305            0 : }
     306              : 
     307              : /* Fix MSVC C99 compatible issue
     308              :  *      MSVC support __func__ from visual studio 2015( 1900 )
     309              :  *      Use MSVC predefine macro to avoid name check fail.
     310              :  */
     311              : #if (defined(_MSC_VER) && (_MSC_VER <= 1900))
     312              : #define /*no-check-names*/ __func__ __FUNCTION__
     313              : #endif
     314              : 
     315              : /* Define `asm` for compilers which don't define it. */
     316              : /* *INDENT-OFF* */
     317              : #ifndef asm
     318              : #if defined(__IAR_SYSTEMS_ICC__)
     319              : #define asm __asm
     320              : #else
     321              : #define asm __asm__
     322              : #endif
     323              : #endif
     324              : /* *INDENT-ON* */
     325              : 
     326              : /*
     327              :  * Define the constraint used for read-only pointer operands to aarch64 asm.
     328              :  *
     329              :  * This is normally the usual "r", but for aarch64_32 (aka ILP32,
     330              :  * as found in watchos), "p" is required to avoid warnings from clang.
     331              :  *
     332              :  * Note that clang does not recognise '+p' or '=p', and armclang
     333              :  * does not recognise 'p' at all. Therefore, to update a pointer from
     334              :  * aarch64 assembly, it is necessary to use something like:
     335              :  *
     336              :  * uintptr_t uptr = (uintptr_t) ptr;
     337              :  * asm( "ldr x4, [%x0], #8" ... : "+r" (uptr) : : )
     338              :  * ptr = (void*) uptr;
     339              :  *
     340              :  * Note that the "x" in "%x0" is neccessary; writing "%0" will cause warnings.
     341              :  */
     342              : #if defined(__aarch64__) && defined(MBEDTLS_HAVE_ASM)
     343              : #if UINTPTR_MAX == 0xfffffffful
     344              : /* ILP32: Specify the pointer operand slightly differently, as per #7787. */
     345              : #define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "p"
     346              : #elif UINTPTR_MAX == 0xfffffffffffffffful
     347              : /* Normal case (64-bit pointers): use "r" as the constraint for pointer operands to asm */
     348              : #define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "r"
     349              : #else
     350              : #error "Unrecognised pointer size for aarch64"
     351              : #endif
     352              : #endif
     353              : 
     354              : /* Always provide a static assert macro, so it can be used unconditionally.
     355              :  * It does nothing on systems where we don't know how to define a static assert.
     356              :  */
     357              : /* Can't use the C11-style `defined(static_assert)` on FreeBSD, since it
     358              :  * defines static_assert even with -std=c99, but then complains about it.
     359              :  */
     360              : #if defined(static_assert) && !defined(__FreeBSD__)
     361              : #define MBEDTLS_STATIC_ASSERT(expr, msg)    static_assert(expr, msg)
     362              : #else
     363              : /* Make sure `MBEDTLS_STATIC_ASSERT(expr, msg);` is valid both inside and
     364              :  * outside a function. We choose a struct declaration, which can be repeated
     365              :  * any number of times and does not need a matching definition. */
     366              : #define MBEDTLS_STATIC_ASSERT(expr, msg)                                \
     367              :     struct ISO_C_does_not_allow_extra_semicolon_outside_of_a_function
     368              : #endif
     369              : 
     370              : #if defined(__has_builtin)
     371              : #define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x)
     372              : #else
     373              : #define MBEDTLS_HAS_BUILTIN(x) 0
     374              : #endif
     375              : 
     376              : /* Define compiler branch hints */
     377              : #if MBEDTLS_HAS_BUILTIN(__builtin_expect)
     378              : #define MBEDTLS_LIKELY(x)       __builtin_expect(!!(x), 1)
     379              : #define MBEDTLS_UNLIKELY(x)     __builtin_expect(!!(x), 0)
     380              : #else
     381              : #define MBEDTLS_LIKELY(x)       x
     382              : #define MBEDTLS_UNLIKELY(x)     x
     383              : #endif
     384              : 
     385              : /* MBEDTLS_ASSUME may be used to provide additional information to the compiler
     386              :  * which can result in smaller code-size. */
     387              : #if MBEDTLS_HAS_BUILTIN(__builtin_assume)
     388              : /* clang provides __builtin_assume */
     389              : #define MBEDTLS_ASSUME(x)       __builtin_assume(x)
     390              : #elif MBEDTLS_HAS_BUILTIN(__builtin_unreachable)
     391              : /* gcc and IAR can use __builtin_unreachable */
     392              : #define MBEDTLS_ASSUME(x)       do { if (!(x)) __builtin_unreachable(); } while (0)
     393              : #elif defined(_MSC_VER)
     394              : /* Supported by MSVC since VS 2005 */
     395              : #define MBEDTLS_ASSUME(x)       __assume(x)
     396              : #else
     397              : #define MBEDTLS_ASSUME(x)       do { } while (0)
     398              : #endif
     399              : 
     400              : /* For gcc -Os, override with -O2 for a given function.
     401              :  *
     402              :  * This will not affect behaviour for other optimisation settings, e.g. -O0.
     403              :  */
     404              : #if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__OPTIMIZE_SIZE__)
     405              : #define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE __attribute__((optimize("-O2")))
     406              : #else
     407              : #define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE
     408              : #endif
     409              : 
     410              : /* Suppress compiler warnings for unused functions and variables. */
     411              : #if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__has_attribute)
     412              : #    if __has_attribute(unused)
     413              : #        define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
     414              : #    endif
     415              : #endif
     416              : #if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__GNUC__)
     417              : #    define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
     418              : #endif
     419              : #if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__IAR_SYSTEMS_ICC__) && defined(__VER__)
     420              : /* IAR does support __attribute__((unused)), but only if the -e flag (extended language support)
     421              :  * is given; the pragma always works.
     422              :  * Unfortunately the pragma affects the rest of the file where it is used, but this is harmless.
     423              :  * Check for version 5.2 or later - this pragma may be supported by earlier versions, but I wasn't
     424              :  * able to find documentation).
     425              :  */
     426              : #    if (__VER__ >= 5020000)
     427              : #        define MBEDTLS_MAYBE_UNUSED _Pragma("diag_suppress=Pe177")
     428              : #    endif
     429              : #endif
     430              : #if !defined(MBEDTLS_MAYBE_UNUSED) && defined(_MSC_VER)
     431              : #    define MBEDTLS_MAYBE_UNUSED __pragma(warning(suppress:4189))
     432              : #endif
     433              : #if !defined(MBEDTLS_MAYBE_UNUSED)
     434              : #    define MBEDTLS_MAYBE_UNUSED
     435              : #endif
     436              : 
     437              : #endif /* MBEDTLS_LIBRARY_COMMON_H */
        

Generated by: LCOV version 2.0-1