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
19using __sanitizer::sptr;
20using __sanitizer::u16;
21using __sanitizer::u8;
22using __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.
33extern "C" {
34
35void __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).
40void __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).
48void __nsan_copy_values(const void *daddr, const void *saddr, uptr size);
49
50SANITIZER_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
62namespace __nsan {
63
64extern bool nsan_initialized;
65extern bool nsan_init_is_running;
66
67void InitializeInterceptors();
68void InitializeMallocInterceptors();
69
70// See notes in nsan_platform.
71inline u8 *GetShadowAddrFor(void *ptr) {
72 uptr AppOffset = ((uptr)ptr) & ShadowMask();
73 return (u8 *)(AppOffset * kShadowScale + ShadowAddr());
74}
75
76inline u8 *GetShadowAddrFor(const void *ptr) {
77 return GetShadowAddrFor(ptr: const_cast<void *>(ptr));
78}
79
80inline u8 *GetShadowTypeAddrFor(void *ptr) {
81 uptr app_offset = ((uptr)ptr) & ShadowMask();
82 return (u8 *)(app_offset + TypesAddr());
83}
84
85inline u8 *GetShadowTypeAddrFor(const void *ptr) {
86 return GetShadowTypeAddrFor(ptr: const_cast<void *>(ptr));
87}
88
89// Information about value types and their shadow counterparts.
90template <typename FT> struct FTInfo {};
91template <> 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};
109template <> 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};
131template <> 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
161template <> 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
171constexpr double kMaxULPDiff = INFINITY;
172
173// Helper for getULPDiff that works on bit representations.
174template <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).
183template <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.
215template <> 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