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 */