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