/ src / secp256k1 / src / checkmem.h
checkmem.h
  1  /***********************************************************************
  2   * Copyright (c) 2022 Pieter Wuille                                    *
  3   * Distributed under the MIT software license, see the accompanying    *
  4   * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
  5   ***********************************************************************/
  6  
  7  /* The code here is inspired by Kris Kwiatkowski's approach in
  8   * https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h
  9   * to provide a general interface for memory-checking mechanisms, primarily
 10   * for constant-time checking.
 11   */
 12  
 13  /* These macros are defined by this header file:
 14   *
 15   * - SECP256K1_CHECKMEM_ENABLED:
 16   *   - 1 if memory-checking integration is available, 0 otherwise.
 17   *     This is just a compile-time macro. Use the next macro to check it is actually
 18   *     available at runtime.
 19   * - SECP256K1_CHECKMEM_RUNNING():
 20   *   - Acts like a function call, returning 1 if memory checking is available
 21   *     at runtime.
 22   * - SECP256K1_CHECKMEM_CHECK(p, len):
 23   *   - Assert or otherwise fail in case the len-byte memory block pointed to by p is
 24   *     not considered entirely defined.
 25   * - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len):
 26   *   - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode.
 27   * - SECP256K1_CHECKMEM_UNDEFINE(p, len):
 28   *   - marks the len-byte memory block pointed to by p as undefined data (secret data,
 29   *     in the context of constant-time checking).
 30   * - SECP256K1_CHECKMEM_DEFINE(p, len):
 31   *   - marks the len-byte memory pointed to by p as defined data (public data, in the
 32   *     context of constant-time checking).
 33   * - SECP256K1_CHECKMEM_MSAN_DEFINE(p, len):
 34   *   - Like SECP256K1_CHECKMEM_DEFINE, but applies only to memory_sanitizer.
 35   *
 36   */
 37  
 38  #ifndef SECP256K1_CHECKMEM_H
 39  #define SECP256K1_CHECKMEM_H
 40  
 41  /* Define a statement-like macro that ignores the arguments. */
 42  #define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0)
 43  
 44  /* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan.
 45   * Choose this preferentially, even when VALGRIND is defined, as msan-compiled
 46   * binaries can't be run under valgrind anyway. */
 47  #if defined(__has_feature)
 48  #  if __has_feature(memory_sanitizer)
 49  #    include <sanitizer/msan_interface.h>
 50  #    define SECP256K1_CHECKMEM_ENABLED 1
 51  #    if defined(__clang__) && ((__clang_major__ == 21 && __clang_minor__ >= 1) || __clang_major__ >= 22)
 52  #      define SECP256K1_CHECKMEM_UNDEFINE(p, len) do { \
 53           /* Work around https://github.com/llvm/llvm-project/issues/160094 */ \
 54           _Pragma("clang diagnostic push") \
 55           _Pragma("clang diagnostic ignored \"-Wuninitialized-const-pointer\"") \
 56           __msan_allocated_memory((p), (len)); \
 57           _Pragma("clang diagnostic pop") \
 58           } while(0)
 59  #    else
 60  #      define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
 61  #    endif
 62  #    define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
 63  #    define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len))
 64  #    define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
 65  #    define SECP256K1_CHECKMEM_RUNNING() (1)
 66  #  endif
 67  #endif
 68  
 69  #if !defined SECP256K1_CHECKMEM_MSAN_DEFINE
 70  #  define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
 71  #endif
 72  
 73  /* If valgrind integration is desired (through the VALGRIND define), implement the
 74   * SECP256K1_CHECKMEM_* macros using valgrind. */
 75  #if !defined SECP256K1_CHECKMEM_ENABLED
 76  #  if defined VALGRIND
 77  #    include <stddef.h>
 78  #  if defined(__clang__) && defined(__APPLE__)
 79  #    pragma clang diagnostic push
 80  #    pragma clang diagnostic ignored "-Wreserved-identifier"
 81  #  elif defined(__GNUC__) && (__GNUC__ >= 15)
 82  #    pragma GCC diagnostic push
 83  #    pragma GCC diagnostic ignored "-Wtrailing-whitespace"
 84  #  endif
 85  #    include <valgrind/memcheck.h>
 86  #  if defined(__clang__) && defined(__APPLE__)
 87  #    pragma clang diagnostic pop
 88  #  elif defined(__GNUC__) && (__GNUC__ >= 15)
 89  #    pragma GCC diagnostic pop
 90  #  endif
 91  #    define SECP256K1_CHECKMEM_ENABLED 1
 92  #    define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len))
 93  #    define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len))
 94  #    define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len))
 95       /* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck.
 96        * This is more precise than the RUNNING_ON_VALGRIND macro, which
 97        * checks for valgrind in general instead of memcheck specifically. */
 98  #    define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0)
 99  #  endif
100  #endif
101  
102  /* As a fall-back, map these macros to dummy statements. */
103  #if !defined SECP256K1_CHECKMEM_ENABLED
104  #  define SECP256K1_CHECKMEM_ENABLED 0
105  #  define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
106  #  define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
107  #  define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
108  #  define SECP256K1_CHECKMEM_RUNNING() (0)
109  #endif
110  
111  #if defined VERIFY
112  #define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len))
113  #else
114  #define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
115  #endif
116  
117  #endif /* SECP256K1_CHECKMEM_H */