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