1 //===-- nsan.h -------------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of NumericalStabilitySanitizer. 10 // 11 // Private NSan header. 12 //===----------------------------------------------------------------------===// 13 14 #ifndef NSAN_H 15 #define NSAN_H 16 17 #include "sanitizer_common/sanitizer_internal_defs.h" 18 19 using __sanitizer::sptr; 20 using __sanitizer::u16; 21 using __sanitizer::u8; 22 using __sanitizer::uptr; 23 24 #include "nsan_platform.h" 25 26 #include <assert.h> 27 #include <float.h> 28 #include <limits.h> 29 #include <math.h> 30 #include <stdio.h> 31 32 // Private nsan interface. Used e.g. by interceptors. 33 extern "C" { 34 35 void __nsan_init(); 36 37 // This marks the shadow type of the given block of application memory as 38 // unknown. 39 // printf-free (see comment in nsan_interceptors.cc). 40 void __nsan_set_value_unknown(const u8 *addr, uptr size); 41 42 // Copies annotations in the shadow memory for a block of application memory to 43 // a new address. This function is used together with memory-copying functions 44 // in application memory, e.g. the instrumentation inserts 45 // `__nsan_copy_values(dest, src, size)` after builtin calls to 46 // `memcpy(dest, src, size)`. Intercepted memcpy calls also call this function. 47 // printf-free (see comment in nsan_interceptors.cc). 48 void __nsan_copy_values(const u8 *daddr, const u8 *saddr, uptr size); 49 50 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char * 51 __nsan_default_options(); 52 } 53 54 namespace __nsan { 55 56 extern bool nsan_initialized; 57 extern bool nsan_init_is_running; 58 59 void InitializeInterceptors(); 60 void InitializeMallocInterceptors(); 61 62 // See notes in nsan_platform. 63 // printf-free (see comment in nsan_interceptors.cc). 64 inline u8 *GetShadowAddrFor(u8 *Ptr) { 65 uptr AppOffset = ((uptr)Ptr) & ShadowMask(); 66 return (u8 *)(AppOffset * kShadowScale + ShadowAddr()); 67 } 68 69 // printf-free (see comment in nsan_interceptors.cc). 70 inline const u8 *GetShadowAddrFor(const u8 *Ptr) { 71 return GetShadowAddrFor(const_cast<u8 *>(Ptr)); 72 } 73 74 // printf-free (see comment in nsan_interceptors.cc). 75 inline u8 *GetShadowTypeAddrFor(u8 *Ptr) { 76 uptr AppOffset = ((uptr)Ptr) & ShadowMask(); 77 return (u8 *)(AppOffset + TypesAddr()); 78 } 79 80 // printf-free (see comment in nsan_interceptors.cc). 81 inline const u8 *GetShadowTypeAddrFor(const u8 *Ptr) { 82 return GetShadowTypeAddrFor(const_cast<u8 *>(Ptr)); 83 } 84 85 // Information about value types and their shadow counterparts. 86 template <typename FT> struct FTInfo {}; 87 template <> struct FTInfo<float> { 88 using orig_type = float; 89 using orig_bits_type = __sanitizer::u32; 90 using mantissa_bits_type = __sanitizer::u32; 91 using shadow_type = double; 92 static const char *kCppTypeName; 93 static constexpr unsigned kMantissaBits = 23; 94 static constexpr int kExponentBits = 8; 95 static constexpr int kExponentBias = 127; 96 static constexpr int kValueType = kFloatValueType; 97 static constexpr char kTypePattern[sizeof(float)] = { 98 static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)), 99 static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)), 100 static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)), 101 static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)), 102 }; 103 static constexpr const float kEpsilon = FLT_EPSILON; 104 }; 105 template <> struct FTInfo<double> { 106 using orig_type = double; 107 using orig_bits_type = __sanitizer::u64; 108 using mantissa_bits_type = __sanitizer::u64; 109 using shadow_type = __float128; 110 static const char *kCppTypeName; 111 static constexpr unsigned kMantissaBits = 52; 112 static constexpr int kExponentBits = 11; 113 static constexpr int kExponentBias = 1023; 114 static constexpr int kValueType = kDoubleValueType; 115 static constexpr char kTypePattern[sizeof(double)] = { 116 static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)), 117 static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)), 118 static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)), 119 static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)), 120 static_cast<unsigned char>(kValueType | (4 << kValueSizeSizeBits)), 121 static_cast<unsigned char>(kValueType | (5 << kValueSizeSizeBits)), 122 static_cast<unsigned char>(kValueType | (6 << kValueSizeSizeBits)), 123 static_cast<unsigned char>(kValueType | (7 << kValueSizeSizeBits)), 124 }; 125 static constexpr const float kEpsilon = DBL_EPSILON; 126 }; 127 template <> struct FTInfo<long double> { 128 using orig_type = long double; 129 using mantissa_bits_type = __sanitizer::u64; 130 using shadow_type = __float128; 131 static const char *kCppTypeName; 132 static constexpr unsigned kMantissaBits = 63; 133 static constexpr int kExponentBits = 15; 134 static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1; 135 static constexpr int kValueType = kFp80ValueType; 136 static constexpr char kTypePattern[sizeof(long double)] = { 137 static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)), 138 static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)), 139 static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)), 140 static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)), 141 static_cast<unsigned char>(kValueType | (4 << kValueSizeSizeBits)), 142 static_cast<unsigned char>(kValueType | (5 << kValueSizeSizeBits)), 143 static_cast<unsigned char>(kValueType | (6 << kValueSizeSizeBits)), 144 static_cast<unsigned char>(kValueType | (7 << kValueSizeSizeBits)), 145 static_cast<unsigned char>(kValueType | (8 << kValueSizeSizeBits)), 146 static_cast<unsigned char>(kValueType | (9 << kValueSizeSizeBits)), 147 static_cast<unsigned char>(kValueType | (10 << kValueSizeSizeBits)), 148 static_cast<unsigned char>(kValueType | (11 << kValueSizeSizeBits)), 149 static_cast<unsigned char>(kValueType | (12 << kValueSizeSizeBits)), 150 static_cast<unsigned char>(kValueType | (13 << kValueSizeSizeBits)), 151 static_cast<unsigned char>(kValueType | (14 << kValueSizeSizeBits)), 152 static_cast<unsigned char>(kValueType | (15 << kValueSizeSizeBits)), 153 }; 154 static constexpr const float kEpsilon = LDBL_EPSILON; 155 }; 156 157 template <> struct FTInfo<__float128> { 158 using orig_type = __float128; 159 using orig_bits_type = __uint128_t; 160 using mantissa_bits_type = __uint128_t; 161 static const char *kCppTypeName; 162 static constexpr unsigned kMantissaBits = 112; 163 static constexpr int kExponentBits = 15; 164 static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1; 165 }; 166 167 constexpr double kMaxULPDiff = INFINITY; 168 169 // Helper for getULPDiff that works on bit representations. 170 template <typename BT> double GetULPDiffBits(BT v1_bits, BT v2_bits) { 171 // If the integer representations of two same-sign floats are subtracted then 172 // the absolute value of the result is equal to one plus the number of 173 // representable floats between them. 174 return v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits; 175 } 176 177 // Returns the the number of floating point values between v1 and v2, capped to 178 // u64max. Return 0 for (-0.0,0.0). 179 template <typename FT> double GetULPDiff(FT v1, FT v2) { 180 if (v1 == v2) { 181 return 0; // Typically, -0.0 and 0.0 182 } 183 using BT = typename FTInfo<FT>::orig_bits_type; 184 static_assert(sizeof(FT) == sizeof(BT), "not implemented"); 185 static_assert(sizeof(BT) <= 64, "not implemented"); 186 BT v1_bits; 187 __builtin_memcpy(&v1_bits, &v1, sizeof(BT)); 188 BT v2_bits; 189 __builtin_memcpy(&v2_bits, &v2, sizeof(BT)); 190 // Check whether the signs differ. IEEE-754 float types always store the sign 191 // in the most significant bit. NaNs and infinities are handled by the calling 192 // code. 193 constexpr BT kSignMask = BT{1} << (CHAR_BIT * sizeof(BT) - 1); 194 if ((v1_bits ^ v2_bits) & kSignMask) { 195 // Signs differ. We can get the ULPs as `getULPDiff(negative_number, -0.0) 196 // + getULPDiff(0.0, positive_number)`. 197 if (v1_bits & kSignMask) { 198 return GetULPDiffBits<BT>(v1_bits, kSignMask) + 199 GetULPDiffBits<BT>(0, v2_bits); 200 } else { 201 return GetULPDiffBits<BT>(v2_bits, kSignMask) + 202 GetULPDiffBits<BT>(0, v1_bits); 203 } 204 } 205 return GetULPDiffBits(v1_bits, v2_bits); 206 } 207 208 // FIXME: This needs mor work: Because there is no 80-bit integer type, we have 209 // to go through __uint128_t. Therefore the assumptions about the sign bit do 210 // not hold. 211 template <> inline double GetULPDiff(long double v1, long double v2) { 212 using BT = __uint128_t; 213 BT v1_bits = 0; 214 __builtin_memcpy(&v1_bits, &v1, sizeof(long double)); 215 BT v2_bits = 0; 216 __builtin_memcpy(&v2_bits, &v2, sizeof(long double)); 217 if ((v1_bits ^ v2_bits) & (BT{1} << (CHAR_BIT * sizeof(BT) - 1))) 218 return v1 == v2 ? __sanitizer::u64{0} : kMaxULPDiff; // Signs differ. 219 // If the integer representations of two same-sign floats are subtracted then 220 // the absolute value of the result is equal to one plus the number of 221 // representable floats between them. 222 BT diff = v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits; 223 return diff >= kMaxULPDiff ? kMaxULPDiff : diff; 224 } 225 226 } // end namespace __nsan 227 228 #endif // NSAN_H 229