| 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 void *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 void *daddr, const void *saddr, uptr size); |
| 49 | |
| 50 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char * |
| 51 | __nsan_default_options(); |
| 52 | } |
| 53 | |
| 54 | // Unwind the stack for fatal error, as the parameter `stack` is |
| 55 | // empty without origins. |
| 56 | #define GET_FATAL_STACK_TRACE_IF_EMPTY(STACK) \ |
| 57 | if (nsan_initialized && (STACK)->size == 0) { \ |
| 58 | (STACK)->Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, \ |
| 59 | common_flags()->fast_unwind_on_fatal); \ |
| 60 | } |
| 61 | |
| 62 | namespace __nsan { |
| 63 | |
| 64 | extern bool nsan_initialized; |
| 65 | extern bool nsan_init_is_running; |
| 66 | |
| 67 | void InitializeInterceptors(); |
| 68 | void InitializeMallocInterceptors(); |
| 69 | |
| 70 | // See notes in nsan_platform. |
| 71 | inline u8 *GetShadowAddrFor(void *ptr) { |
| 72 | uptr AppOffset = ((uptr)ptr) & ShadowMask(); |
| 73 | return (u8 *)(AppOffset * kShadowScale + ShadowAddr()); |
| 74 | } |
| 75 | |
| 76 | inline u8 *GetShadowAddrFor(const void *ptr) { |
| 77 | return GetShadowAddrFor(ptr: const_cast<void *>(ptr)); |
| 78 | } |
| 79 | |
| 80 | inline u8 *GetShadowTypeAddrFor(void *ptr) { |
| 81 | uptr app_offset = ((uptr)ptr) & ShadowMask(); |
| 82 | return (u8 *)(app_offset + TypesAddr()); |
| 83 | } |
| 84 | |
| 85 | inline u8 *GetShadowTypeAddrFor(const void *ptr) { |
| 86 | return GetShadowTypeAddrFor(ptr: const_cast<void *>(ptr)); |
| 87 | } |
| 88 | |
| 89 | // Information about value types and their shadow counterparts. |
| 90 | template <typename FT> struct FTInfo {}; |
| 91 | template <> struct FTInfo<float> { |
| 92 | using orig_type = float; |
| 93 | using orig_bits_type = u32; |
| 94 | using mantissa_bits_type = u32; |
| 95 | using shadow_type = double; |
| 96 | static const char *kCppTypeName; |
| 97 | static constexpr unsigned kMantissaBits = 23; |
| 98 | static constexpr int kExponentBits = 8; |
| 99 | static constexpr int kExponentBias = 127; |
| 100 | static constexpr int kValueType = kFloatValueType; |
| 101 | static constexpr char kTypePattern[sizeof(float)] = { |
| 102 | static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)), |
| 103 | static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)), |
| 104 | static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)), |
| 105 | static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)), |
| 106 | }; |
| 107 | static constexpr const float kEpsilon = FLT_EPSILON; |
| 108 | }; |
| 109 | template <> struct FTInfo<double> { |
| 110 | using orig_type = double; |
| 111 | using orig_bits_type = u64; |
| 112 | using mantissa_bits_type = u64; |
| 113 | using shadow_type = __float128; |
| 114 | static const char *kCppTypeName; |
| 115 | static constexpr unsigned kMantissaBits = 52; |
| 116 | static constexpr int kExponentBits = 11; |
| 117 | static constexpr int kExponentBias = 1023; |
| 118 | static constexpr int kValueType = kDoubleValueType; |
| 119 | static constexpr char kTypePattern[sizeof(double)] = { |
| 120 | static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)), |
| 121 | static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)), |
| 122 | static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)), |
| 123 | static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)), |
| 124 | static_cast<unsigned char>(kValueType | (4 << kValueSizeSizeBits)), |
| 125 | static_cast<unsigned char>(kValueType | (5 << kValueSizeSizeBits)), |
| 126 | static_cast<unsigned char>(kValueType | (6 << kValueSizeSizeBits)), |
| 127 | static_cast<unsigned char>(kValueType | (7 << kValueSizeSizeBits)), |
| 128 | }; |
| 129 | static constexpr const float kEpsilon = DBL_EPSILON; |
| 130 | }; |
| 131 | template <> struct FTInfo<long double> { |
| 132 | using orig_type = long double; |
| 133 | using mantissa_bits_type = u64; |
| 134 | using shadow_type = __float128; |
| 135 | static const char *kCppTypeName; |
| 136 | static constexpr unsigned kMantissaBits = 63; |
| 137 | static constexpr int kExponentBits = 15; |
| 138 | static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1; |
| 139 | static constexpr int kValueType = kFp80ValueType; |
| 140 | static constexpr char kTypePattern[sizeof(long double)] = { |
| 141 | static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)), |
| 142 | static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)), |
| 143 | static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)), |
| 144 | static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)), |
| 145 | static_cast<unsigned char>(kValueType | (4 << kValueSizeSizeBits)), |
| 146 | static_cast<unsigned char>(kValueType | (5 << kValueSizeSizeBits)), |
| 147 | static_cast<unsigned char>(kValueType | (6 << kValueSizeSizeBits)), |
| 148 | static_cast<unsigned char>(kValueType | (7 << kValueSizeSizeBits)), |
| 149 | static_cast<unsigned char>(kValueType | (8 << kValueSizeSizeBits)), |
| 150 | static_cast<unsigned char>(kValueType | (9 << kValueSizeSizeBits)), |
| 151 | static_cast<unsigned char>(kValueType | (10 << kValueSizeSizeBits)), |
| 152 | static_cast<unsigned char>(kValueType | (11 << kValueSizeSizeBits)), |
| 153 | static_cast<unsigned char>(kValueType | (12 << kValueSizeSizeBits)), |
| 154 | static_cast<unsigned char>(kValueType | (13 << kValueSizeSizeBits)), |
| 155 | static_cast<unsigned char>(kValueType | (14 << kValueSizeSizeBits)), |
| 156 | static_cast<unsigned char>(kValueType | (15 << kValueSizeSizeBits)), |
| 157 | }; |
| 158 | static constexpr const float kEpsilon = LDBL_EPSILON; |
| 159 | }; |
| 160 | |
| 161 | template <> struct FTInfo<__float128> { |
| 162 | using orig_type = __float128; |
| 163 | using orig_bits_type = __uint128_t; |
| 164 | using mantissa_bits_type = __uint128_t; |
| 165 | static const char *kCppTypeName; |
| 166 | static constexpr unsigned kMantissaBits = 112; |
| 167 | static constexpr int kExponentBits = 15; |
| 168 | static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1; |
| 169 | }; |
| 170 | |
| 171 | constexpr double kMaxULPDiff = INFINITY; |
| 172 | |
| 173 | // Helper for getULPDiff that works on bit representations. |
| 174 | template <typename BT> double GetULPDiffBits(BT v1_bits, BT v2_bits) { |
| 175 | // If the integer representations of two same-sign floats are subtracted then |
| 176 | // the absolute value of the result is equal to one plus the number of |
| 177 | // representable floats between them. |
| 178 | return v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits; |
| 179 | } |
| 180 | |
| 181 | // Returns the the number of floating point values between v1 and v2, capped to |
| 182 | // u64max. Return 0 for (-0.0,0.0). |
| 183 | template <typename FT> double GetULPDiff(FT v1, FT v2) { |
| 184 | if (v1 == v2) { |
| 185 | return 0; // Typically, -0.0 and 0.0 |
| 186 | } |
| 187 | using BT = typename FTInfo<FT>::orig_bits_type; |
| 188 | static_assert(sizeof(FT) == sizeof(BT), "not implemented" ); |
| 189 | static_assert(sizeof(BT) <= 64, "not implemented" ); |
| 190 | BT v1_bits; |
| 191 | __builtin_memcpy(&v1_bits, &v1, sizeof(BT)); |
| 192 | BT v2_bits; |
| 193 | __builtin_memcpy(&v2_bits, &v2, sizeof(BT)); |
| 194 | // Check whether the signs differ. IEEE-754 float types always store the sign |
| 195 | // in the most significant bit. NaNs and infinities are handled by the calling |
| 196 | // code. |
| 197 | constexpr BT kSignMask = BT{1} << (CHAR_BIT * sizeof(BT) - 1); |
| 198 | if ((v1_bits ^ v2_bits) & kSignMask) { |
| 199 | // Signs differ. We can get the ULPs as `getULPDiff(negative_number, -0.0) |
| 200 | // + getULPDiff(0.0, positive_number)`. |
| 201 | if (v1_bits & kSignMask) { |
| 202 | return GetULPDiffBits<BT>(v1_bits, kSignMask) + |
| 203 | GetULPDiffBits<BT>(0, v2_bits); |
| 204 | } else { |
| 205 | return GetULPDiffBits<BT>(v2_bits, kSignMask) + |
| 206 | GetULPDiffBits<BT>(0, v1_bits); |
| 207 | } |
| 208 | } |
| 209 | return GetULPDiffBits(v1_bits, v2_bits); |
| 210 | } |
| 211 | |
| 212 | // FIXME: This needs mor work: Because there is no 80-bit integer type, we have |
| 213 | // to go through __uint128_t. Therefore the assumptions about the sign bit do |
| 214 | // not hold. |
| 215 | template <> inline double GetULPDiff(long double v1, long double v2) { |
| 216 | using BT = __uint128_t; |
| 217 | BT v1_bits = 0; |
| 218 | __builtin_memcpy(&v1_bits, &v1, sizeof(long double)); |
| 219 | BT v2_bits = 0; |
| 220 | __builtin_memcpy(&v2_bits, &v2, sizeof(long double)); |
| 221 | if ((v1_bits ^ v2_bits) & (BT{1} << (CHAR_BIT * sizeof(BT) - 1))) |
| 222 | return v1 == v2 ? __sanitizer::u64{0} : kMaxULPDiff; // Signs differ. |
| 223 | // If the integer representations of two same-sign floats are subtracted then |
| 224 | // the absolute value of the result is equal to one plus the number of |
| 225 | // representable floats between them. |
| 226 | BT diff = v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits; |
| 227 | return diff >= kMaxULPDiff ? kMaxULPDiff : diff; |
| 228 | } |
| 229 | |
| 230 | } // end namespace __nsan |
| 231 | |
| 232 | #endif // NSAN_H |
| 233 | |