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.cpp
35233 views
1
//===-- nsan.cc -----------------------------------------------------------===//
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
// NumericalStabilitySanitizer runtime.
10
//
11
// This implements:
12
// - The public nsan interface (include/sanitizer/nsan_interface.h).
13
// - The private nsan interface (./nsan.h).
14
// - The internal instrumentation interface. These are function emitted by the
15
// instrumentation pass:
16
// * __nsan_get_shadow_ptr_for_{float,double,longdouble}_load
17
// These return the shadow memory pointer for loading the shadow value,
18
// after checking that the types are consistent. If the types are not
19
// consistent, returns nullptr.
20
// * __nsan_get_shadow_ptr_for_{float,double,longdouble}_store
21
// Sets the shadow types appropriately and returns the shadow memory
22
// pointer for storing the shadow value.
23
// * __nsan_internal_check_{float,double,long double}_{f,d,l} checks the
24
// accuracy of a value against its shadow and emits a warning depending
25
// on the runtime configuration. The middle part indicates the type of
26
// the application value, the suffix (f,d,l) indicates the type of the
27
// shadow, and depends on the instrumentation configuration.
28
// * __nsan_fcmp_fail_* emits a warning for an fcmp instruction whose
29
// corresponding shadow fcmp result differs.
30
//
31
//===----------------------------------------------------------------------===//
32
33
#include <assert.h>
34
#include <math.h>
35
#include <stdint.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
39
#include "sanitizer_common/sanitizer_atomic.h"
40
#include "sanitizer_common/sanitizer_common.h"
41
#include "sanitizer_common/sanitizer_libc.h"
42
#include "sanitizer_common/sanitizer_report_decorator.h"
43
#include "sanitizer_common/sanitizer_stacktrace.h"
44
#include "sanitizer_common/sanitizer_symbolizer.h"
45
46
#include "nsan/nsan.h"
47
#include "nsan/nsan_flags.h"
48
#include "nsan/nsan_stats.h"
49
#include "nsan/nsan_suppressions.h"
50
51
using namespace __sanitizer;
52
using namespace __nsan;
53
54
constexpr int kMaxVectorWidth = 8;
55
56
// When copying application memory, we also copy its shadow and shadow type.
57
// FIXME: We could provide fixed-size versions that would nicely
58
// vectorize for known sizes.
59
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
60
__nsan_copy_values(const u8 *daddr, const u8 *saddr, uptr size) {
61
internal_memmove((void *)GetShadowTypeAddrFor(daddr),
62
GetShadowTypeAddrFor(saddr), size);
63
internal_memmove((void *)GetShadowAddrFor(daddr), GetShadowAddrFor(saddr),
64
size * kShadowScale);
65
}
66
67
// FIXME: We could provide fixed-size versions that would nicely
68
// vectorize for known sizes.
69
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
70
__nsan_set_value_unknown(const u8 *addr, uptr size) {
71
internal_memset((void *)GetShadowTypeAddrFor(addr), 0, size);
72
}
73
74
75
const char *FTInfo<float>::kCppTypeName = "float";
76
const char *FTInfo<double>::kCppTypeName = "double";
77
const char *FTInfo<long double>::kCppTypeName = "long double";
78
const char *FTInfo<__float128>::kCppTypeName = "__float128";
79
80
const char FTInfo<float>::kTypePattern[sizeof(float)];
81
const char FTInfo<double>::kTypePattern[sizeof(double)];
82
const char FTInfo<long double>::kTypePattern[sizeof(long double)];
83
84
// Helper for __nsan_dump_shadow_mem: Reads the value at address `ptr`,
85
// identified by its type id.
86
template <typename ShadowFT>
87
static __float128 ReadShadowInternal(const u8 *ptr) {
88
ShadowFT Shadow;
89
__builtin_memcpy(&Shadow, ptr, sizeof(Shadow));
90
return Shadow;
91
}
92
93
static __float128 ReadShadow(const u8 *ptr, const char ShadowTypeId) {
94
switch (ShadowTypeId) {
95
case 'd':
96
return ReadShadowInternal<double>(ptr);
97
case 'l':
98
return ReadShadowInternal<long double>(ptr);
99
case 'q':
100
return ReadShadowInternal<__float128>(ptr);
101
default:
102
return 0.0;
103
}
104
}
105
106
namespace {
107
class Decorator : public __sanitizer::SanitizerCommonDecorator {
108
public:
109
Decorator() : SanitizerCommonDecorator() {}
110
const char *Warning() { return Red(); }
111
const char *Name() { return Green(); }
112
const char *End() { return Default(); }
113
};
114
115
// Workaround for the fact that Printf() does not support floats.
116
struct PrintBuffer {
117
char Buffer[64];
118
};
119
template <typename FT> struct FTPrinter {};
120
121
template <> struct FTPrinter<double> {
122
static PrintBuffer dec(double value) {
123
PrintBuffer result;
124
snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20f", value);
125
return result;
126
}
127
static PrintBuffer hex(double value) {
128
PrintBuffer result;
129
snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20a", value);
130
return result;
131
}
132
};
133
134
template <> struct FTPrinter<float> : FTPrinter<double> {};
135
136
template <> struct FTPrinter<long double> {
137
static PrintBuffer dec(long double value) {
138
PrintBuffer result;
139
snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20Lf", value);
140
return result;
141
}
142
static PrintBuffer hex(long double value) {
143
PrintBuffer result;
144
snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20La", value);
145
return result;
146
}
147
};
148
149
// FIXME: print with full precision.
150
template <> struct FTPrinter<__float128> : FTPrinter<long double> {};
151
152
// This is a template so that there are no implicit conversions.
153
template <typename FT> inline FT ftAbs(FT v);
154
155
template <> inline long double ftAbs(long double v) { return fabsl(v); }
156
template <> inline double ftAbs(double v) { return fabs(v); }
157
158
// We don't care about nans.
159
// std::abs(__float128) code is suboptimal and generates a function call to
160
// __getf2().
161
template <typename FT> inline FT ftAbs(FT v) { return v >= FT{0} ? v : -v; }
162
163
template <typename FT1, typename FT2, bool Enable> struct LargestFTImpl {
164
using type = FT2;
165
};
166
167
template <typename FT1, typename FT2> struct LargestFTImpl<FT1, FT2, true> {
168
using type = FT1;
169
};
170
171
template <typename FT1, typename FT2>
172
using LargestFT =
173
typename LargestFTImpl<FT1, FT2, (sizeof(FT1) > sizeof(FT2))>::type;
174
175
template <typename T> T max(T a, T b) { return a < b ? b : a; }
176
177
} // end anonymous namespace
178
179
void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
180
void *context,
181
bool request_fast,
182
u32 max_depth) {
183
using namespace __nsan;
184
return Unwind(max_depth, pc, bp, context, 0, 0, false);
185
}
186
187
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_print_accumulated_stats() {
188
if (nsan_stats)
189
nsan_stats->Print();
190
}
191
192
static void NsanAtexit() {
193
Printf("Numerical Sanitizer exit stats:\n");
194
__nsan_print_accumulated_stats();
195
nsan_stats = nullptr;
196
}
197
198
// The next three functions return a pointer for storing a shadow value for `n`
199
// values, after setting the shadow types. We return the pointer instead of
200
// storing ourselves because it avoids having to rely on the calling convention
201
// around long double being the same for nsan and the target application.
202
// We have to have 3 versions because we need to know which type we are storing
203
// since we are setting the type shadow memory.
204
template <typename FT> static u8 *getShadowPtrForStore(u8 *store_addr, uptr n) {
205
unsigned char *shadow_type = GetShadowTypeAddrFor(store_addr);
206
for (uptr i = 0; i < n; ++i) {
207
__builtin_memcpy(shadow_type + i * sizeof(FT), FTInfo<FT>::kTypePattern,
208
sizeof(FTInfo<FT>::kTypePattern));
209
}
210
return GetShadowAddrFor(store_addr);
211
}
212
213
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
214
__nsan_get_shadow_ptr_for_float_store(u8 *store_addr, uptr n) {
215
return getShadowPtrForStore<float>(store_addr, n);
216
}
217
218
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
219
__nsan_get_shadow_ptr_for_double_store(u8 *store_addr, uptr n) {
220
return getShadowPtrForStore<double>(store_addr, n);
221
}
222
223
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
224
__nsan_get_shadow_ptr_for_longdouble_store(u8 *store_addr, uptr n) {
225
return getShadowPtrForStore<long double>(store_addr, n);
226
}
227
228
template <typename FT> static bool IsValidShadowType(const u8 *shadow_type) {
229
return __builtin_memcmp(shadow_type, FTInfo<FT>::kTypePattern, sizeof(FT)) ==
230
0;
231
}
232
233
template <int kSize, typename T> static bool IsZero(const T *ptr) {
234
constexpr const char kZeros[kSize] = {}; // Zero initialized.
235
return __builtin_memcmp(ptr, kZeros, kSize) == 0;
236
}
237
238
template <typename FT> static bool IsUnknownShadowType(const u8 *shadow_type) {
239
return IsZero<sizeof(FTInfo<FT>::kTypePattern)>(shadow_type);
240
}
241
242
// The three folowing functions check that the address stores a complete
243
// shadow value of the given type and return a pointer for loading.
244
// They return nullptr if the type of the value is unknown or incomplete.
245
template <typename FT>
246
static const u8 *getShadowPtrForLoad(const u8 *load_addr, uptr n) {
247
const u8 *const shadow_type = GetShadowTypeAddrFor(load_addr);
248
for (uptr i = 0; i < n; ++i) {
249
if (!IsValidShadowType<FT>(shadow_type + i * sizeof(FT))) {
250
// If loadtracking stats are enabled, log loads with invalid types
251
// (tampered with through type punning).
252
if (flags().enable_loadtracking_stats) {
253
if (IsUnknownShadowType<FT>(shadow_type + i * sizeof(FT))) {
254
// Warn only if the value is non-zero. Zero is special because
255
// applications typically initialize large buffers to zero in an
256
// untyped way.
257
if (!IsZero<sizeof(FT)>(load_addr)) {
258
GET_CALLER_PC_BP;
259
nsan_stats->AddUnknownLoadTrackingEvent(pc, bp);
260
}
261
} else {
262
GET_CALLER_PC_BP;
263
nsan_stats->AddInvalidLoadTrackingEvent(pc, bp);
264
}
265
}
266
return nullptr;
267
}
268
}
269
return GetShadowAddrFor(load_addr);
270
}
271
272
extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
273
__nsan_get_shadow_ptr_for_float_load(const u8 *load_addr, uptr n) {
274
return getShadowPtrForLoad<float>(load_addr, n);
275
}
276
277
extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
278
__nsan_get_shadow_ptr_for_double_load(const u8 *load_addr, uptr n) {
279
return getShadowPtrForLoad<double>(load_addr, n);
280
}
281
282
extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
283
__nsan_get_shadow_ptr_for_longdouble_load(const u8 *load_addr, uptr n) {
284
return getShadowPtrForLoad<long double>(load_addr, n);
285
}
286
287
// Returns the raw shadow pointer. The returned pointer should be considered
288
// opaque.
289
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
290
__nsan_internal_get_raw_shadow_ptr(const u8 *addr) {
291
return GetShadowAddrFor(const_cast<u8 *>(addr));
292
}
293
294
// Returns the raw shadow type pointer. The returned pointer should be
295
// considered opaque.
296
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
297
__nsan_internal_get_raw_shadow_type_ptr(const u8 *addr) {
298
return reinterpret_cast<u8 *>(GetShadowTypeAddrFor(const_cast<u8 *>(addr)));
299
}
300
301
static ValueType getValueType(u8 c) { return static_cast<ValueType>(c & 0x3); }
302
303
static int getValuePos(u8 c) { return c >> kValueSizeSizeBits; }
304
305
// Checks the consistency of the value types at the given type pointer.
306
// If the value is inconsistent, returns ValueType::kUnknown. Else, return the
307
// consistent type.
308
template <typename FT>
309
static bool checkValueConsistency(const u8 *shadow_type) {
310
const int pos = getValuePos(*shadow_type);
311
// Check that all bytes from the start of the value are ordered.
312
for (uptr i = 0; i < sizeof(FT); ++i) {
313
const u8 T = *(shadow_type - pos + i);
314
if (!(getValueType(T) == FTInfo<FT>::kValueType && getValuePos(T) == i))
315
return false;
316
}
317
return true;
318
}
319
320
// The instrumentation automatically appends `shadow_value_type_ids`, see
321
// maybeAddSuffixForNsanInterface.
322
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
323
__nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line,
324
size_t shadow_value_type_ids) {
325
const u8 *const shadow_type = GetShadowTypeAddrFor(addr);
326
const u8 *const shadow = GetShadowAddrFor(addr);
327
328
constexpr int kMaxNumDecodedValues = 16;
329
__float128 decoded_values[kMaxNumDecodedValues];
330
int num_decoded_values = 0;
331
if (bytes_per_line > 4 * kMaxNumDecodedValues)
332
bytes_per_line = 4 * kMaxNumDecodedValues;
333
334
// We keep track of the current type and position as we go.
335
ValueType LastValueTy = kUnknownValueType;
336
int LastPos = -1;
337
size_t Offset = 0;
338
for (size_t R = 0; R < (size_bytes + bytes_per_line - 1) / bytes_per_line;
339
++R) {
340
printf("%p: ", (void *)(addr + R * bytes_per_line));
341
for (size_t C = 0; C < bytes_per_line && Offset < size_bytes; ++C) {
342
const ValueType ValueTy = getValueType(shadow_type[Offset]);
343
const int pos = getValuePos(shadow_type[Offset]);
344
if (ValueTy == LastValueTy && pos == LastPos + 1) {
345
++LastPos;
346
} else {
347
LastValueTy = ValueTy;
348
LastPos = pos == 0 ? 0 : -1;
349
}
350
351
switch (ValueTy) {
352
case kUnknownValueType:
353
printf("__ ");
354
break;
355
case kFloatValueType:
356
printf("f%x ", pos);
357
if (LastPos == sizeof(float) - 1) {
358
decoded_values[num_decoded_values] =
359
ReadShadow(shadow + kShadowScale * (Offset + 1 - sizeof(float)),
360
static_cast<char>(shadow_value_type_ids & 0xff));
361
++num_decoded_values;
362
}
363
break;
364
case kDoubleValueType:
365
printf("d%x ", pos);
366
if (LastPos == sizeof(double) - 1) {
367
decoded_values[num_decoded_values] = ReadShadow(
368
shadow + kShadowScale * (Offset + 1 - sizeof(double)),
369
static_cast<char>((shadow_value_type_ids >> 8) & 0xff));
370
++num_decoded_values;
371
}
372
break;
373
case kFp80ValueType:
374
printf("l%x ", pos);
375
if (LastPos == sizeof(long double) - 1) {
376
decoded_values[num_decoded_values] = ReadShadow(
377
shadow + kShadowScale * (Offset + 1 - sizeof(long double)),
378
static_cast<char>((shadow_value_type_ids >> 16) & 0xff));
379
++num_decoded_values;
380
}
381
break;
382
}
383
++Offset;
384
}
385
for (int i = 0; i < num_decoded_values; ++i) {
386
printf(" (%s)", FTPrinter<__float128>::dec(decoded_values[i]).Buffer);
387
}
388
num_decoded_values = 0;
389
printf("\n");
390
}
391
}
392
393
alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
394
thread_local uptr __nsan_shadow_ret_tag = 0;
395
396
alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
397
thread_local char __nsan_shadow_ret_ptr[kMaxVectorWidth *
398
sizeof(__float128)];
399
400
alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
401
thread_local uptr __nsan_shadow_args_tag = 0;
402
403
// Maximum number of args. This should be enough for anyone (tm). An alternate
404
// scheme is to have the generated code create an alloca and make
405
// __nsan_shadow_args_ptr point ot the alloca.
406
constexpr const int kMaxNumArgs = 128;
407
alignas(16) SANITIZER_INTERFACE_ATTRIBUTE
408
thread_local char __nsan_shadow_args_ptr[kMaxVectorWidth * kMaxNumArgs *
409
sizeof(__float128)];
410
411
enum ContinuationType { // Keep in sync with instrumentation pass.
412
kContinueWithShadow = 0,
413
kResumeFromValue = 1,
414
};
415
416
// Checks the consistency between application and shadow value. Returns true
417
// when the instrumented code should resume computations from the original value
418
// rather than the shadow value. This prevents one error to propagate to all
419
// subsequent operations. This behaviour is tunable with flags.
420
template <typename FT, typename ShadowFT>
421
int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,
422
uptr CheckArg) {
423
// We do all comparisons in the InternalFT domain, which is the largest FT
424
// type.
425
using InternalFT = LargestFT<FT, ShadowFT>;
426
const InternalFT check_value = value;
427
const InternalFT check_shadow = Shadow;
428
429
// See this article for an interesting discussion of how to compare floats:
430
// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
431
static constexpr const FT Eps = FTInfo<FT>::kEpsilon;
432
433
const InternalFT abs_err = ftAbs(check_value - check_shadow);
434
435
if (flags().enable_check_stats) {
436
GET_CALLER_PC_BP;
437
// We are re-computing `largest` here because this is a cold branch, and we
438
// want to avoid having to move the computation of `largest` before the
439
// absolute value check when this branch is not taken.
440
const InternalFT largest = max(ftAbs(check_value), ftAbs(check_shadow));
441
nsan_stats->AddCheck(CheckType, pc, bp, abs_err / largest);
442
}
443
444
// Note: writing the comparison that way ensures that when `abs_err` is Nan
445
// (value and shadow are inf or -inf), we pass the test.
446
if (!(abs_err >= flags().cached_absolute_error_threshold))
447
return kContinueWithShadow;
448
449
const InternalFT largest = max(ftAbs(check_value), ftAbs(check_shadow));
450
if (abs_err * (1ull << flags().log2_max_relative_error) <= largest)
451
return kContinueWithShadow; // No problem here.
452
453
if (!flags().disable_warnings) {
454
GET_CALLER_PC_BP;
455
BufferedStackTrace stack;
456
stack.Unwind(pc, bp, nullptr, false);
457
if (GetSuppressionForStack(&stack, CheckKind::Consistency)) {
458
// FIXME: optionally print.
459
return flags().resume_after_suppression ? kResumeFromValue
460
: kContinueWithShadow;
461
}
462
463
Decorator D;
464
Printf("%s", D.Warning());
465
// Printf does not support float formatting.
466
char RelErrBuf[64] = "inf";
467
if (largest > Eps) {
468
snprintf(RelErrBuf, sizeof(RelErrBuf) - 1, "%.20Lf%% (2^%.0Lf epsilons)",
469
static_cast<long double>(100.0 * abs_err / largest),
470
log2l(static_cast<long double>(abs_err / largest / Eps)));
471
}
472
char ulp_err_buf[128] = "";
473
const double shadow_ulp_diff = GetULPDiff(check_value, check_shadow);
474
if (shadow_ulp_diff != kMaxULPDiff) {
475
// This is the ULP diff in the internal domain. The user actually cares
476
// about that in the original domain.
477
const double ulp_diff =
478
shadow_ulp_diff / (u64{1} << (FTInfo<InternalFT>::kMantissaBits -
479
FTInfo<FT>::kMantissaBits));
480
snprintf(ulp_err_buf, sizeof(ulp_err_buf) - 1,
481
"(%.0f ULPs == %.1f digits == %.1f bits)", ulp_diff,
482
log10(ulp_diff), log2(ulp_diff));
483
}
484
Printf("WARNING: NumericalStabilitySanitizer: inconsistent shadow results");
485
switch (CheckType) {
486
case CheckTypeT::kUnknown:
487
case CheckTypeT::kFcmp:
488
case CheckTypeT::kMaxCheckType:
489
break;
490
case CheckTypeT::kRet:
491
Printf(" while checking return value");
492
break;
493
case CheckTypeT::kArg:
494
Printf(" while checking call argument #%d", static_cast<int>(CheckArg));
495
break;
496
case CheckTypeT::kLoad:
497
Printf(
498
" while checking load from address 0x%lx. This is due to incorrect "
499
"shadow memory tracking, typically due to uninstrumented code "
500
"writing to memory.",
501
CheckArg);
502
break;
503
case CheckTypeT::kStore:
504
Printf(" while checking store to address 0x%lx", CheckArg);
505
break;
506
case CheckTypeT::kInsert:
507
Printf(" while checking vector insert");
508
break;
509
case CheckTypeT::kUser:
510
Printf(" in user-initiated check");
511
break;
512
}
513
using ValuePrinter = FTPrinter<FT>;
514
using ShadowPrinter = FTPrinter<ShadowFT>;
515
Printf("%s", D.Default());
516
517
Printf("\n"
518
"%-12s precision (native): dec: %s hex: %s\n"
519
"%-12s precision (shadow): dec: %s hex: %s\n"
520
"shadow truncated to %-12s: dec: %s hex: %s\n"
521
"Relative error: %s\n"
522
"Absolute error: %s\n"
523
"%s\n",
524
FTInfo<FT>::kCppTypeName, ValuePrinter::dec(value).Buffer,
525
ValuePrinter::hex(value).Buffer, FTInfo<ShadowFT>::kCppTypeName,
526
ShadowPrinter::dec(Shadow).Buffer, ShadowPrinter::hex(Shadow).Buffer,
527
FTInfo<FT>::kCppTypeName, ValuePrinter::dec(Shadow).Buffer,
528
ValuePrinter::hex(Shadow).Buffer, RelErrBuf,
529
ValuePrinter::hex(abs_err).Buffer, ulp_err_buf);
530
stack.Print();
531
}
532
533
if (flags().enable_warning_stats) {
534
GET_CALLER_PC_BP;
535
nsan_stats->AddWarning(CheckType, pc, bp, abs_err / largest);
536
}
537
538
if (flags().halt_on_error) {
539
if (common_flags()->abort_on_error)
540
Printf("ABORTING\n");
541
else
542
Printf("Exiting\n");
543
Die();
544
}
545
return flags().resume_after_warning ? kResumeFromValue : kContinueWithShadow;
546
}
547
548
extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_float_d(
549
float value, double shadow, int32_t check_type, uptr check_arg) {
550
return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);
551
}
552
553
extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_double_l(
554
double value, long double shadow, int32_t check_type, uptr check_arg) {
555
return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);
556
}
557
558
extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_double_q(
559
double value, __float128 shadow, int32_t check_type, uptr check_arg) {
560
return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);
561
}
562
563
extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t
564
__nsan_internal_check_longdouble_q(long double value, __float128 shadow,
565
int32_t check_type, uptr check_arg) {
566
return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);
567
}
568
569
static const char *GetTruthValueName(bool v) { return v ? "true" : "false"; }
570
571
// This uses the same values as CmpInst::Predicate.
572
static const char *GetPredicateName(int v) {
573
switch (v) {
574
case 0:
575
return "(false)";
576
case 1:
577
return "==";
578
case 2:
579
return ">";
580
case 3:
581
return ">=";
582
case 4:
583
return "<";
584
case 5:
585
return "<=";
586
case 6:
587
return "!=";
588
case 7:
589
return "(ordered)";
590
case 8:
591
return "(unordered)";
592
case 9:
593
return "==";
594
case 10:
595
return ">";
596
case 11:
597
return ">=";
598
case 12:
599
return "<";
600
case 13:
601
return "<=";
602
case 14:
603
return "!=";
604
case 15:
605
return "(true)";
606
}
607
return "??";
608
}
609
610
template <typename FT, typename ShadowFT>
611
void fCmpFailFT(const FT Lhs, const FT Rhs, ShadowFT LhsShadow,
612
ShadowFT RhsShadow, int Predicate, bool result,
613
bool ShadowResult) {
614
if (result == ShadowResult) {
615
// When a vector comparison fails, we fail each element of the comparison
616
// to simplify instrumented code. Skip elements where the shadow comparison
617
// gave the same result as the original one.
618
return;
619
}
620
621
GET_CALLER_PC_BP;
622
BufferedStackTrace stack;
623
stack.Unwind(pc, bp, nullptr, false);
624
625
if (GetSuppressionForStack(&stack, CheckKind::Fcmp)) {
626
// FIXME: optionally print.
627
return;
628
}
629
630
if (flags().enable_warning_stats)
631
nsan_stats->AddWarning(CheckTypeT::kFcmp, pc, bp, 0.0);
632
633
if (flags().disable_warnings)
634
return;
635
636
// FIXME: ideally we would print the shadow value as FP128. Right now because
637
// we truncate to long double we can sometimes see stuff like:
638
// shadow <value> == <value> (false)
639
using ValuePrinter = FTPrinter<FT>;
640
using ShadowPrinter = FTPrinter<ShadowFT>;
641
Decorator D;
642
const char *const PredicateName = GetPredicateName(Predicate);
643
Printf("%s", D.Warning());
644
Printf("WARNING: NumericalStabilitySanitizer: floating-point comparison "
645
"results depend on precision\n");
646
Printf("%s", D.Default());
647
Printf("%-12s precision dec (native): %s %s %s (%s)\n"
648
"%-12s precision dec (shadow): %s %s %s (%s)\n"
649
"%-12s precision hex (native): %s %s %s (%s)\n"
650
"%-12s precision hex (shadow): %s %s %s (%s)\n"
651
"%s",
652
// Native, decimal.
653
FTInfo<FT>::kCppTypeName, ValuePrinter::dec(Lhs).Buffer, PredicateName,
654
ValuePrinter::dec(Rhs).Buffer, GetTruthValueName(result),
655
// Shadow, decimal
656
FTInfo<ShadowFT>::kCppTypeName, ShadowPrinter::dec(LhsShadow).Buffer,
657
PredicateName, ShadowPrinter::dec(RhsShadow).Buffer,
658
GetTruthValueName(ShadowResult),
659
// Native, hex.
660
FTInfo<FT>::kCppTypeName, ValuePrinter::hex(Lhs).Buffer, PredicateName,
661
ValuePrinter::hex(Rhs).Buffer, GetTruthValueName(result),
662
// Shadow, hex
663
FTInfo<ShadowFT>::kCppTypeName, ShadowPrinter::hex(LhsShadow).Buffer,
664
PredicateName, ShadowPrinter::hex(RhsShadow).Buffer,
665
GetTruthValueName(ShadowResult), D.End());
666
stack.Print();
667
if (flags().halt_on_error) {
668
Printf("Exiting\n");
669
Die();
670
}
671
}
672
673
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
674
__nsan_fcmp_fail_float_d(float lhs, float rhs, double lhs_shadow,
675
double rhs_shadow, int predicate, bool result,
676
bool shadow_result) {
677
fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,
678
shadow_result);
679
}
680
681
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
682
__nsan_fcmp_fail_double_q(double lhs, double rhs, __float128 lhs_shadow,
683
__float128 rhs_shadow, int predicate, bool result,
684
bool shadow_result) {
685
fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,
686
shadow_result);
687
}
688
689
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
690
__nsan_fcmp_fail_double_l(double lhs, double rhs, long double lhs_shadow,
691
long double rhs_shadow, int predicate, bool result,
692
bool shadow_result) {
693
fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,
694
shadow_result);
695
}
696
697
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
698
__nsan_fcmp_fail_longdouble_q(long double lhs, long double rhs,
699
__float128 lhs_shadow, __float128 rhs_shadow,
700
int predicate, bool result, bool shadow_result) {
701
fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,
702
shadow_result);
703
}
704
705
template <typename FT> void checkFTFromShadowStack(const FT value) {
706
// Get the shadow 2FT value from the shadow stack. Note that
707
// __nsan_check_{float,double,long double} is a function like any other, so
708
// the instrumentation will have placed the shadow value on the shadow stack.
709
using ShadowFT = typename FTInfo<FT>::shadow_type;
710
ShadowFT Shadow;
711
__builtin_memcpy(&Shadow, __nsan_shadow_args_ptr, sizeof(ShadowFT));
712
checkFT(value, Shadow, CheckTypeT::kUser, 0);
713
}
714
715
// FIXME: Add suffixes and let the instrumentation pass automatically add
716
// suffixes.
717
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_check_float(float value) {
718
assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_float &&
719
"__nsan_check_float called from non-instrumented function");
720
checkFTFromShadowStack(value);
721
}
722
723
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
724
__nsan_check_double(double value) {
725
assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_double &&
726
"__nsan_check_double called from non-instrumented function");
727
checkFTFromShadowStack(value);
728
}
729
730
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
731
__nsan_check_longdouble(long double value) {
732
assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_longdouble &&
733
"__nsan_check_longdouble called from non-instrumented function");
734
checkFTFromShadowStack(value);
735
}
736
737
template <typename FT> static void dumpFTFromShadowStack(const FT value) {
738
// Get the shadow 2FT value from the shadow stack. Note that
739
// __nsan_dump_{float,double,long double} is a function like any other, so
740
// the instrumentation will have placed the shadow value on the shadow stack.
741
using ShadowFT = typename FTInfo<FT>::shadow_type;
742
ShadowFT shadow;
743
__builtin_memcpy(&shadow, __nsan_shadow_args_ptr, sizeof(ShadowFT));
744
using ValuePrinter = FTPrinter<FT>;
745
using ShadowPrinter = FTPrinter<typename FTInfo<FT>::shadow_type>;
746
printf("value dec:%s hex:%s\n"
747
"shadow dec:%s hex:%s\n",
748
ValuePrinter::dec(value).Buffer, ValuePrinter::hex(value).Buffer,
749
ShadowPrinter::dec(shadow).Buffer, ShadowPrinter::hex(shadow).Buffer);
750
}
751
752
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_float(float value) {
753
assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_float &&
754
"__nsan_dump_float called from non-instrumented function");
755
dumpFTFromShadowStack(value);
756
}
757
758
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_double(double value) {
759
assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_double &&
760
"__nsan_dump_double called from non-instrumented function");
761
dumpFTFromShadowStack(value);
762
}
763
764
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
765
__nsan_dump_longdouble(long double value) {
766
assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_longdouble &&
767
"__nsan_dump_longdouble called from non-instrumented function");
768
dumpFTFromShadowStack(value);
769
}
770
771
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_ret() {
772
printf("ret tag: %lx\n", __nsan_shadow_ret_tag);
773
double v;
774
__builtin_memcpy(&v, __nsan_shadow_ret_ptr, sizeof(double));
775
printf("double value: %f\n", v);
776
// FIXME: float128 value.
777
}
778
779
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_args() {
780
printf("args tag: %lx\n", __nsan_shadow_args_tag);
781
}
782
783
bool __nsan::nsan_initialized;
784
bool __nsan::nsan_init_is_running;
785
786
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_init() {
787
CHECK(!nsan_init_is_running);
788
if (nsan_initialized)
789
return;
790
nsan_init_is_running = true;
791
792
InitializeFlags();
793
InitializeSuppressions();
794
InitializePlatformEarly();
795
796
DisableCoreDumperIfNecessary();
797
798
if (!MmapFixedNoReserve(TypesAddr(), UnusedAddr() - TypesAddr()))
799
Die();
800
801
InitializeInterceptors();
802
803
InitializeStats();
804
if (flags().print_stats_on_exit)
805
Atexit(NsanAtexit);
806
807
nsan_init_is_running = false;
808
nsan_initialized = true;
809
}
810
811