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(Ptr: 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(Ptr: 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 | |