Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/nsan/nsan.h
35233 views
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
230