1 //===-- nsan.cc -----------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // NumericalStabilitySanitizer runtime.
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 a fcmp instruction whose
29 // corresponding shadow fcmp result differs.
31 //===----------------------------------------------------------------------===//
34 #include "nsan_flags.h"
35 #include "nsan_stats.h"
36 #include "nsan_suppressions.h"
37 #include "nsan_thread.h"
45 #include "sanitizer_common/sanitizer_atomic.h"
46 #include "sanitizer_common/sanitizer_common.h"
47 #include "sanitizer_common/sanitizer_libc.h"
48 #include "sanitizer_common/sanitizer_report_decorator.h"
49 #include "sanitizer_common/sanitizer_stacktrace.h"
50 #include "sanitizer_common/sanitizer_symbolizer.h"
52 using namespace __sanitizer
;
53 using namespace __nsan
;
55 constexpr int kMaxVectorWidth
= 8;
57 // When copying application memory, we also copy its shadow and shadow type.
58 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
59 __nsan_copy_values(const void *daddr
, const void *saddr
, uptr size
) {
60 internal_memmove(GetShadowTypeAddrFor(daddr
), GetShadowTypeAddrFor(saddr
),
62 internal_memmove(GetShadowAddrFor(daddr
), GetShadowAddrFor(saddr
),
66 #define NSAN_COPY_VALUES_N(N) \
67 extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_copy_##N( \
68 const u8 *daddr, const u8 *saddr) { \
69 __builtin_memmove(GetShadowTypeAddrFor(daddr), \
70 GetShadowTypeAddrFor(saddr), N); \
71 __builtin_memmove(GetShadowAddrFor(daddr), GetShadowAddrFor(saddr), \
77 NSAN_COPY_VALUES_N(16)
79 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
80 __nsan_set_value_unknown(const void *addr
, uptr size
) {
81 internal_memset(GetShadowTypeAddrFor(addr
), 0, size
);
84 #define NSAN_SET_VALUE_UNKNOWN_N(N) \
85 extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_set_value_unknown_##N( \
87 __builtin_memset(GetShadowTypeAddrFor(daddr), 0, N); \
90 NSAN_SET_VALUE_UNKNOWN_N(4)
91 NSAN_SET_VALUE_UNKNOWN_N(8)
92 NSAN_SET_VALUE_UNKNOWN_N(16)
94 const char *FTInfo
<float>::kCppTypeName
= "float";
95 const char *FTInfo
<double>::kCppTypeName
= "double";
96 const char *FTInfo
<long double>::kCppTypeName
= "long double";
97 const char *FTInfo
<__float128
>::kCppTypeName
= "__float128";
99 const char FTInfo
<float>::kTypePattern
[sizeof(float)];
100 const char FTInfo
<double>::kTypePattern
[sizeof(double)];
101 const char FTInfo
<long double>::kTypePattern
[sizeof(long double)];
103 // Helper for __nsan_dump_shadow_mem: Reads the value at address `ptr`,
104 // identified by its type id.
105 template <typename ShadowFT
>
106 static __float128
ReadShadowInternal(const u8
*ptr
) {
108 __builtin_memcpy(&Shadow
, ptr
, sizeof(Shadow
));
112 static __float128
ReadShadow(const u8
*ptr
, const char ShadowTypeId
) {
113 switch (ShadowTypeId
) {
115 return ReadShadowInternal
<double>(ptr
);
117 return ReadShadowInternal
<long double>(ptr
);
119 return ReadShadowInternal
<__float128
>(ptr
);
126 class Decorator
: public __sanitizer::SanitizerCommonDecorator
{
128 Decorator() : SanitizerCommonDecorator() {}
129 const char *Warning() { return Red(); }
130 const char *Name() { return Green(); }
131 const char *End() { return Default(); }
134 // Workaround for the fact that Printf() does not support floats.
138 template <typename FT
> struct FTPrinter
{};
140 template <> struct FTPrinter
<double> {
141 static PrintBuffer
dec(double value
) {
143 snprintf(result
.Buffer
, sizeof(result
.Buffer
) - 1, "%.20f", value
);
146 static PrintBuffer
hex(double value
) {
148 snprintf(result
.Buffer
, sizeof(result
.Buffer
) - 1, "%.20a", value
);
153 template <> struct FTPrinter
<float> : FTPrinter
<double> {};
155 template <> struct FTPrinter
<long double> {
156 static PrintBuffer
dec(long double value
) {
158 snprintf(result
.Buffer
, sizeof(result
.Buffer
) - 1, "%.20Lf", value
);
161 static PrintBuffer
hex(long double value
) {
163 snprintf(result
.Buffer
, sizeof(result
.Buffer
) - 1, "%.20La", value
);
168 // FIXME: print with full precision.
169 template <> struct FTPrinter
<__float128
> : FTPrinter
<long double> {};
171 // This is a template so that there are no implicit conversions.
172 template <typename FT
> inline FT
ftAbs(FT v
);
174 template <> inline long double ftAbs(long double v
) { return fabsl(v
); }
175 template <> inline double ftAbs(double v
) { return fabs(v
); }
177 // We don't care about nans.
178 // std::abs(__float128) code is suboptimal and generates a function call to
180 template <typename FT
> inline FT
ftAbs(FT v
) { return v
>= FT
{0} ? v
: -v
; }
182 template <typename FT1
, typename FT2
, bool Enable
> struct LargestFTImpl
{
186 template <typename FT1
, typename FT2
> struct LargestFTImpl
<FT1
, FT2
, true> {
190 template <typename FT1
, typename FT2
>
192 typename LargestFTImpl
<FT1
, FT2
, (sizeof(FT1
) > sizeof(FT2
))>::type
;
194 template <typename T
> T
max(T a
, T b
) { return a
< b
? b
: a
; }
196 } // end anonymous namespace
198 void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc
, uptr bp
,
202 using namespace __nsan
;
203 NsanThread
*t
= GetCurrentThread();
204 if (!t
|| !StackTrace::WillUseFastUnwind(request_fast
))
205 return Unwind(max_depth
, pc
, bp
, context
, t
? t
->stack_top() : 0,
206 t
? t
->stack_bottom() : 0, false);
207 if (StackTrace::WillUseFastUnwind(request_fast
))
208 Unwind(max_depth
, pc
, bp
, nullptr, t
->stack_top(), t
->stack_bottom(), true);
210 Unwind(max_depth
, pc
, 0, context
, 0, 0, false);
213 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __nsan_print_accumulated_stats() {
218 static void NsanAtexit() {
219 Printf("Numerical Sanitizer exit stats:\n");
220 __nsan_print_accumulated_stats();
221 nsan_stats
= nullptr;
224 // The next three functions return a pointer for storing a shadow value for `n`
225 // values, after setting the shadow types. We return the pointer instead of
226 // storing ourselves because it avoids having to rely on the calling convention
227 // around long double being the same for nsan and the target application.
228 // We have to have 3 versions because we need to know which type we are storing
229 // since we are setting the type shadow memory.
230 template <typename FT
> static u8
*getShadowPtrForStore(u8
*store_addr
, uptr n
) {
231 unsigned char *shadow_type
= GetShadowTypeAddrFor(store_addr
);
232 for (uptr i
= 0; i
< n
; ++i
) {
233 __builtin_memcpy(shadow_type
+ i
* sizeof(FT
), FTInfo
<FT
>::kTypePattern
,
234 sizeof(FTInfo
<FT
>::kTypePattern
));
236 return GetShadowAddrFor(store_addr
);
239 extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8
*
240 __nsan_get_shadow_ptr_for_float_store(u8
*store_addr
, uptr n
) {
241 return getShadowPtrForStore
<float>(store_addr
, n
);
244 extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8
*
245 __nsan_get_shadow_ptr_for_double_store(u8
*store_addr
, uptr n
) {
246 return getShadowPtrForStore
<double>(store_addr
, n
);
249 extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8
*
250 __nsan_get_shadow_ptr_for_longdouble_store(u8
*store_addr
, uptr n
) {
251 return getShadowPtrForStore
<long double>(store_addr
, n
);
254 template <typename FT
> static bool IsValidShadowType(const u8
*shadow_type
) {
255 return __builtin_memcmp(shadow_type
, FTInfo
<FT
>::kTypePattern
, sizeof(FT
)) ==
259 template <int kSize
, typename T
> static bool IsZero(const T
*ptr
) {
260 constexpr const char kZeros
[kSize
] = {}; // Zero initialized.
261 return __builtin_memcmp(ptr
, kZeros
, kSize
) == 0;
264 template <typename FT
> static bool IsUnknownShadowType(const u8
*shadow_type
) {
265 return IsZero
<sizeof(FTInfo
<FT
>::kTypePattern
)>(shadow_type
);
268 // The three folowing functions check that the address stores a complete
269 // shadow value of the given type and return a pointer for loading.
270 // They return nullptr if the type of the value is unknown or incomplete.
271 template <typename FT
>
272 static const u8
*getShadowPtrForLoad(const u8
*load_addr
, uptr n
) {
273 const u8
*const shadow_type
= GetShadowTypeAddrFor(load_addr
);
274 for (uptr i
= 0; i
< n
; ++i
) {
275 if (!IsValidShadowType
<FT
>(shadow_type
+ i
* sizeof(FT
))) {
276 // If loadtracking stats are enabled, log loads with invalid types
277 // (tampered with through type punning).
278 if (flags().enable_loadtracking_stats
) {
279 if (IsUnknownShadowType
<FT
>(shadow_type
+ i
* sizeof(FT
))) {
280 // Warn only if the value is non-zero. Zero is special because
281 // applications typically initialize large buffers to zero in an
283 if (!IsZero
<sizeof(FT
)>(load_addr
)) {
285 nsan_stats
->AddUnknownLoadTrackingEvent(pc
, bp
);
289 nsan_stats
->AddInvalidLoadTrackingEvent(pc
, bp
);
295 return GetShadowAddrFor(load_addr
);
298 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
const u8
*
299 __nsan_get_shadow_ptr_for_float_load(const u8
*load_addr
, uptr n
) {
300 return getShadowPtrForLoad
<float>(load_addr
, n
);
303 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
const u8
*
304 __nsan_get_shadow_ptr_for_double_load(const u8
*load_addr
, uptr n
) {
305 return getShadowPtrForLoad
<double>(load_addr
, n
);
308 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
const u8
*
309 __nsan_get_shadow_ptr_for_longdouble_load(const u8
*load_addr
, uptr n
) {
310 return getShadowPtrForLoad
<long double>(load_addr
, n
);
313 // Returns the raw shadow pointer. The returned pointer should be considered
315 extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8
*
316 __nsan_internal_get_raw_shadow_ptr(const u8
*addr
) {
317 return GetShadowAddrFor(addr
);
320 // Returns the raw shadow type pointer. The returned pointer should be
321 // considered opaque.
322 extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8
*
323 __nsan_internal_get_raw_shadow_type_ptr(const u8
*addr
) {
324 return reinterpret_cast<u8
*>(GetShadowTypeAddrFor(addr
));
327 static ValueType
getValueType(u8 c
) { return static_cast<ValueType
>(c
& 0x3); }
329 static int getValuePos(u8 c
) { return c
>> kValueSizeSizeBits
; }
331 // Checks the consistency of the value types at the given type pointer.
332 // If the value is inconsistent, returns ValueType::kUnknown. Else, return the
334 template <typename FT
>
335 static bool checkValueConsistency(const u8
*shadow_type
) {
336 const int pos
= getValuePos(*shadow_type
);
337 // Check that all bytes from the start of the value are ordered.
338 for (uptr i
= 0; i
< sizeof(FT
); ++i
) {
339 const u8 T
= *(shadow_type
- pos
+ i
);
340 if (!(getValueType(T
) == FTInfo
<FT
>::kValueType
&& getValuePos(T
) == i
))
346 // The instrumentation automatically appends `shadow_value_type_ids`, see
347 // maybeAddSuffixForNsanInterface.
348 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
349 __nsan_dump_shadow_mem(const u8
*addr
, size_t size_bytes
, size_t bytes_per_line
,
350 size_t shadow_value_type_ids
) {
351 const u8
*const shadow_type
= GetShadowTypeAddrFor(addr
);
352 const u8
*const shadow
= GetShadowAddrFor(addr
);
354 constexpr int kMaxNumDecodedValues
= 16;
355 __float128 decoded_values
[kMaxNumDecodedValues
];
356 int num_decoded_values
= 0;
357 if (bytes_per_line
> 4 * kMaxNumDecodedValues
)
358 bytes_per_line
= 4 * kMaxNumDecodedValues
;
360 // We keep track of the current type and position as we go.
361 ValueType LastValueTy
= kUnknownValueType
;
364 for (size_t R
= 0; R
< (size_bytes
+ bytes_per_line
- 1) / bytes_per_line
;
366 printf("%p: ", (void *)(addr
+ R
* bytes_per_line
));
367 for (size_t C
= 0; C
< bytes_per_line
&& Offset
< size_bytes
; ++C
) {
368 const ValueType ValueTy
= getValueType(shadow_type
[Offset
]);
369 const int pos
= getValuePos(shadow_type
[Offset
]);
370 if (ValueTy
== LastValueTy
&& pos
== LastPos
+ 1) {
373 LastValueTy
= ValueTy
;
374 LastPos
= pos
== 0 ? 0 : -1;
378 case kUnknownValueType
:
381 case kFloatValueType
:
383 if (LastPos
== sizeof(float) - 1) {
384 decoded_values
[num_decoded_values
] =
385 ReadShadow(shadow
+ kShadowScale
* (Offset
+ 1 - sizeof(float)),
386 static_cast<char>(shadow_value_type_ids
& 0xff));
387 ++num_decoded_values
;
390 case kDoubleValueType
:
392 if (LastPos
== sizeof(double) - 1) {
393 decoded_values
[num_decoded_values
] = ReadShadow(
394 shadow
+ kShadowScale
* (Offset
+ 1 - sizeof(double)),
395 static_cast<char>((shadow_value_type_ids
>> 8) & 0xff));
396 ++num_decoded_values
;
401 if (LastPos
== sizeof(long double) - 1) {
402 decoded_values
[num_decoded_values
] = ReadShadow(
403 shadow
+ kShadowScale
* (Offset
+ 1 - sizeof(long double)),
404 static_cast<char>((shadow_value_type_ids
>> 16) & 0xff));
405 ++num_decoded_values
;
411 for (int i
= 0; i
< num_decoded_values
; ++i
) {
412 printf(" (%s)", FTPrinter
<__float128
>::dec(decoded_values
[i
]).Buffer
);
414 num_decoded_values
= 0;
419 alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
420 thread_local uptr __nsan_shadow_ret_tag
= 0;
422 alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
423 thread_local
char __nsan_shadow_ret_ptr
[kMaxVectorWidth
*
426 alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
427 thread_local uptr __nsan_shadow_args_tag
= 0;
429 // Maximum number of args. This should be enough for anyone (tm). An alternate
430 // scheme is to have the generated code create an alloca and make
431 // __nsan_shadow_args_ptr point ot the alloca.
432 constexpr const int kMaxNumArgs
= 128;
433 alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
434 thread_local
char __nsan_shadow_args_ptr
[kMaxVectorWidth
* kMaxNumArgs
*
437 enum ContinuationType
{ // Keep in sync with instrumentation pass.
438 kContinueWithShadow
= 0,
439 kResumeFromValue
= 1,
442 // Checks the consistency between application and shadow value. Returns true
443 // when the instrumented code should resume computations from the original value
444 // rather than the shadow value. This prevents one error to propagate to all
445 // subsequent operations. This behaviour is tunable with flags.
446 template <typename FT
, typename ShadowFT
>
447 int32_t checkFT(const FT value
, ShadowFT Shadow
, CheckTypeT CheckType
,
449 // We do all comparisons in the InternalFT domain, which is the largest FT
451 using InternalFT
= LargestFT
<FT
, ShadowFT
>;
452 const InternalFT check_value
= value
;
453 const InternalFT check_shadow
= Shadow
;
455 // We only check for NaNs in the value, not the shadow.
456 if (flags().check_nan
&& isnan(value
)) {
458 BufferedStackTrace stack
;
459 stack
.Unwind(pc
, bp
, nullptr, false);
460 if (GetSuppressionForStack(&stack
, CheckKind::Consistency
)) {
461 // FIXME: optionally print.
462 return flags().resume_after_suppression
? kResumeFromValue
463 : kContinueWithShadow
;
466 Printf("%s", D
.Warning());
467 Printf("WARNING: NumericalStabilitySanitizer: NaN detected\n");
468 Printf("%s", D
.Default());
470 if (flags().halt_on_error
) {
471 if (common_flags()->abort_on_error
)
472 Printf("ABORTING\n");
477 // Performing other tests for NaN values is meaningless when dealing with numbers.
478 return kResumeFromValue
;
481 // See this article for an interesting discussion of how to compare floats:
482 // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
483 static constexpr const FT Eps
= FTInfo
<FT
>::kEpsilon
;
485 const InternalFT abs_err
= ftAbs(check_value
- check_shadow
);
487 if (flags().enable_check_stats
) {
489 // We are re-computing `largest` here because this is a cold branch, and we
490 // want to avoid having to move the computation of `largest` before the
491 // absolute value check when this branch is not taken.
492 const InternalFT largest
= max(ftAbs(check_value
), ftAbs(check_shadow
));
493 nsan_stats
->AddCheck(CheckType
, pc
, bp
, abs_err
/ largest
);
496 // Note: writing the comparison that way ensures that when `abs_err` is Nan
497 // (value and shadow are inf or -inf), we pass the test.
498 if (!(abs_err
>= flags().cached_absolute_error_threshold
))
499 return kContinueWithShadow
;
501 const InternalFT largest
= max(ftAbs(check_value
), ftAbs(check_shadow
));
502 if (abs_err
* (1ull << flags().log2_max_relative_error
) <= largest
)
503 return kContinueWithShadow
; // No problem here.
505 if (!flags().disable_warnings
) {
507 UNINITIALIZED BufferedStackTrace stack
;
508 stack
.Unwind(pc
, bp
, nullptr, false);
509 if (GetSuppressionForStack(&stack
, CheckKind::Consistency
)) {
510 // FIXME: optionally print.
511 return flags().resume_after_suppression
? kResumeFromValue
512 : kContinueWithShadow
;
516 Printf("%s", D
.Warning());
517 // Printf does not support float formatting.
518 char RelErrBuf
[64] = "inf";
520 snprintf(RelErrBuf
, sizeof(RelErrBuf
) - 1, "%.20Lf%% (2^%.0Lf epsilons)",
521 static_cast<long double>(100.0 * abs_err
/ largest
),
522 log2l(static_cast<long double>(abs_err
/ largest
/ Eps
)));
524 char ulp_err_buf
[128] = "";
525 const double shadow_ulp_diff
= GetULPDiff(check_value
, check_shadow
);
526 if (shadow_ulp_diff
!= kMaxULPDiff
) {
527 // This is the ULP diff in the internal domain. The user actually cares
528 // about that in the original domain.
529 const double ulp_diff
=
530 shadow_ulp_diff
/ (u64
{1} << (FTInfo
<InternalFT
>::kMantissaBits
-
531 FTInfo
<FT
>::kMantissaBits
));
532 snprintf(ulp_err_buf
, sizeof(ulp_err_buf
) - 1,
533 "(%.0f ULPs == %.1f digits == %.1f bits)", ulp_diff
,
534 log10(ulp_diff
), log2(ulp_diff
));
536 Printf("WARNING: NumericalStabilitySanitizer: inconsistent shadow results");
538 case CheckTypeT::kUnknown
:
539 case CheckTypeT::kFcmp
:
540 case CheckTypeT::kMaxCheckType
:
542 case CheckTypeT::kRet
:
543 Printf(" while checking return value");
545 case CheckTypeT::kArg
:
546 Printf(" while checking call argument #%d", static_cast<int>(CheckArg
));
548 case CheckTypeT::kLoad
:
550 " while checking load from address 0x%lx. This is due to incorrect "
551 "shadow memory tracking, typically due to uninstrumented code "
552 "writing to memory.",
555 case CheckTypeT::kStore
:
556 Printf(" while checking store to address 0x%lx", CheckArg
);
558 case CheckTypeT::kInsert
:
559 Printf(" while checking vector insert");
561 case CheckTypeT::kUser
:
562 Printf(" in user-initiated check");
565 using ValuePrinter
= FTPrinter
<FT
>;
566 using ShadowPrinter
= FTPrinter
<ShadowFT
>;
567 Printf("%s", D
.Default());
570 "%-12s precision (native): dec: %s hex: %s\n"
571 "%-12s precision (shadow): dec: %s hex: %s\n"
572 "shadow truncated to %-12s: dec: %s hex: %s\n"
573 "Relative error: %s\n"
574 "Absolute error: %s\n"
576 FTInfo
<FT
>::kCppTypeName
, ValuePrinter::dec(value
).Buffer
,
577 ValuePrinter::hex(value
).Buffer
, FTInfo
<ShadowFT
>::kCppTypeName
,
578 ShadowPrinter::dec(Shadow
).Buffer
, ShadowPrinter::hex(Shadow
).Buffer
,
579 FTInfo
<FT
>::kCppTypeName
, ValuePrinter::dec(Shadow
).Buffer
,
580 ValuePrinter::hex(Shadow
).Buffer
, RelErrBuf
,
581 ValuePrinter::hex(abs_err
).Buffer
, ulp_err_buf
);
585 if (flags().enable_warning_stats
) {
587 nsan_stats
->AddWarning(CheckType
, pc
, bp
, abs_err
/ largest
);
590 if (flags().halt_on_error
) {
591 if (common_flags()->abort_on_error
)
592 Printf("ABORTING\n");
597 return flags().resume_after_warning
? kResumeFromValue
: kContinueWithShadow
;
600 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
int32_t __nsan_internal_check_float_d(
601 float value
, double shadow
, int32_t check_type
, uptr check_arg
) {
602 return checkFT(value
, shadow
, static_cast<CheckTypeT
>(check_type
), check_arg
);
605 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
int32_t __nsan_internal_check_double_l(
606 double value
, long double shadow
, int32_t check_type
, uptr check_arg
) {
607 return checkFT(value
, shadow
, static_cast<CheckTypeT
>(check_type
), check_arg
);
610 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
int32_t __nsan_internal_check_double_q(
611 double value
, __float128 shadow
, int32_t check_type
, uptr check_arg
) {
612 return checkFT(value
, shadow
, static_cast<CheckTypeT
>(check_type
), check_arg
);
615 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
int32_t
616 __nsan_internal_check_longdouble_q(long double value
, __float128 shadow
,
617 int32_t check_type
, uptr check_arg
) {
618 return checkFT(value
, shadow
, static_cast<CheckTypeT
>(check_type
), check_arg
);
621 static const char *GetTruthValueName(bool v
) { return v
? "true" : "false"; }
623 // This uses the same values as CmpInst::Predicate.
624 static const char *GetPredicateName(int v
) {
643 return "(unordered)";
662 template <typename FT
, typename ShadowFT
>
663 void fCmpFailFT(const FT Lhs
, const FT Rhs
, ShadowFT LhsShadow
,
664 ShadowFT RhsShadow
, int Predicate
, bool result
,
666 if (result
== ShadowResult
) {
667 // When a vector comparison fails, we fail each element of the comparison
668 // to simplify instrumented code. Skip elements where the shadow comparison
669 // gave the same result as the original one.
674 UNINITIALIZED BufferedStackTrace stack
;
675 stack
.Unwind(pc
, bp
, nullptr, false);
677 if (GetSuppressionForStack(&stack
, CheckKind::Fcmp
)) {
678 // FIXME: optionally print.
682 if (flags().enable_warning_stats
)
683 nsan_stats
->AddWarning(CheckTypeT::kFcmp
, pc
, bp
, 0.0);
685 if (flags().disable_warnings
|| !flags().check_cmp
)
688 // FIXME: ideally we would print the shadow value as FP128. Right now because
689 // we truncate to long double we can sometimes see stuff like:
690 // shadow <value> == <value> (false)
691 using ValuePrinter
= FTPrinter
<FT
>;
692 using ShadowPrinter
= FTPrinter
<ShadowFT
>;
694 const char *const PredicateName
= GetPredicateName(Predicate
);
695 Printf("%s", D
.Warning());
696 Printf("WARNING: NumericalStabilitySanitizer: floating-point comparison "
697 "results depend on precision\n");
698 Printf("%s", D
.Default());
699 Printf("%-12s precision dec (native): %s %s %s (%s)\n"
700 "%-12s precision dec (shadow): %s %s %s (%s)\n"
701 "%-12s precision hex (native): %s %s %s (%s)\n"
702 "%-12s precision hex (shadow): %s %s %s (%s)\n"
705 FTInfo
<FT
>::kCppTypeName
, ValuePrinter::dec(Lhs
).Buffer
, PredicateName
,
706 ValuePrinter::dec(Rhs
).Buffer
, GetTruthValueName(result
),
708 FTInfo
<ShadowFT
>::kCppTypeName
, ShadowPrinter::dec(LhsShadow
).Buffer
,
709 PredicateName
, ShadowPrinter::dec(RhsShadow
).Buffer
,
710 GetTruthValueName(ShadowResult
),
712 FTInfo
<FT
>::kCppTypeName
, ValuePrinter::hex(Lhs
).Buffer
, PredicateName
,
713 ValuePrinter::hex(Rhs
).Buffer
, GetTruthValueName(result
),
715 FTInfo
<ShadowFT
>::kCppTypeName
, ShadowPrinter::hex(LhsShadow
).Buffer
,
716 PredicateName
, ShadowPrinter::hex(RhsShadow
).Buffer
,
717 GetTruthValueName(ShadowResult
), D
.End());
719 if (flags().halt_on_error
) {
725 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
726 __nsan_fcmp_fail_float_d(float lhs
, float rhs
, double lhs_shadow
,
727 double rhs_shadow
, int predicate
, bool result
,
728 bool shadow_result
) {
729 fCmpFailFT(lhs
, rhs
, lhs_shadow
, rhs_shadow
, predicate
, result
,
733 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
734 __nsan_fcmp_fail_double_q(double lhs
, double rhs
, __float128 lhs_shadow
,
735 __float128 rhs_shadow
, int predicate
, bool result
,
736 bool shadow_result
) {
737 fCmpFailFT(lhs
, rhs
, lhs_shadow
, rhs_shadow
, predicate
, result
,
741 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
742 __nsan_fcmp_fail_double_l(double lhs
, double rhs
, long double lhs_shadow
,
743 long double rhs_shadow
, int predicate
, bool result
,
744 bool shadow_result
) {
745 fCmpFailFT(lhs
, rhs
, lhs_shadow
, rhs_shadow
, predicate
, result
,
749 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
750 __nsan_fcmp_fail_longdouble_q(long double lhs
, long double rhs
,
751 __float128 lhs_shadow
, __float128 rhs_shadow
,
752 int predicate
, bool result
, bool shadow_result
) {
753 fCmpFailFT(lhs
, rhs
, lhs_shadow
, rhs_shadow
, predicate
, result
,
757 template <typename FT
> void checkFTFromShadowStack(const FT value
) {
758 // Get the shadow 2FT value from the shadow stack. Note that
759 // __nsan_check_{float,double,long double} is a function like any other, so
760 // the instrumentation will have placed the shadow value on the shadow stack.
761 using ShadowFT
= typename FTInfo
<FT
>::shadow_type
;
763 __builtin_memcpy(&Shadow
, __nsan_shadow_args_ptr
, sizeof(ShadowFT
));
764 checkFT(value
, Shadow
, CheckTypeT::kUser
, 0);
767 // FIXME: Add suffixes and let the instrumentation pass automatically add
769 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __nsan_check_float(float value
) {
770 assert(__nsan_shadow_args_tag
== (uptr
)&__nsan_check_float
&&
771 "__nsan_check_float called from non-instrumented function");
772 checkFTFromShadowStack(value
);
775 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
776 __nsan_check_double(double value
) {
777 assert(__nsan_shadow_args_tag
== (uptr
)&__nsan_check_double
&&
778 "__nsan_check_double called from non-instrumented function");
779 checkFTFromShadowStack(value
);
782 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
783 __nsan_check_longdouble(long double value
) {
784 assert(__nsan_shadow_args_tag
== (uptr
)&__nsan_check_longdouble
&&
785 "__nsan_check_longdouble called from non-instrumented function");
786 checkFTFromShadowStack(value
);
789 template <typename FT
> static void dumpFTFromShadowStack(const FT value
) {
790 // Get the shadow 2FT value from the shadow stack. Note that
791 // __nsan_dump_{float,double,long double} is a function like any other, so
792 // the instrumentation will have placed the shadow value on the shadow stack.
793 using ShadowFT
= typename FTInfo
<FT
>::shadow_type
;
795 __builtin_memcpy(&shadow
, __nsan_shadow_args_ptr
, sizeof(ShadowFT
));
796 using ValuePrinter
= FTPrinter
<FT
>;
797 using ShadowPrinter
= FTPrinter
<typename FTInfo
<FT
>::shadow_type
>;
798 printf("value dec:%s hex:%s\n"
799 "shadow dec:%s hex:%s\n",
800 ValuePrinter::dec(value
).Buffer
, ValuePrinter::hex(value
).Buffer
,
801 ShadowPrinter::dec(shadow
).Buffer
, ShadowPrinter::hex(shadow
).Buffer
);
804 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __nsan_dump_float(float value
) {
805 assert(__nsan_shadow_args_tag
== (uptr
)&__nsan_dump_float
&&
806 "__nsan_dump_float called from non-instrumented function");
807 dumpFTFromShadowStack(value
);
810 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __nsan_dump_double(double value
) {
811 assert(__nsan_shadow_args_tag
== (uptr
)&__nsan_dump_double
&&
812 "__nsan_dump_double called from non-instrumented function");
813 dumpFTFromShadowStack(value
);
816 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void
817 __nsan_dump_longdouble(long double value
) {
818 assert(__nsan_shadow_args_tag
== (uptr
)&__nsan_dump_longdouble
&&
819 "__nsan_dump_longdouble called from non-instrumented function");
820 dumpFTFromShadowStack(value
);
823 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __nsan_dump_shadow_ret() {
824 printf("ret tag: %lx\n", __nsan_shadow_ret_tag
);
826 __builtin_memcpy(&v
, __nsan_shadow_ret_ptr
, sizeof(double));
827 printf("double value: %f\n", v
);
828 // FIXME: float128 value.
831 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __nsan_dump_shadow_args() {
832 printf("args tag: %lx\n", __nsan_shadow_args_tag
);
835 bool __nsan::nsan_initialized
;
836 bool __nsan::nsan_init_is_running
;
838 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __nsan_init() {
839 CHECK(!nsan_init_is_running
);
840 if (nsan_initialized
)
842 nsan_init_is_running
= true;
843 SanitizerToolName
= "NumericalStabilitySanitizer";
846 InitializeSuppressions();
847 InitializePlatformEarly();
849 DisableCoreDumperIfNecessary();
851 if (!MmapFixedNoReserve(TypesAddr(), AllocatorAddr() - TypesAddr()))
854 InitializeInterceptors();
855 NsanTSDInit(NsanTSDDtor
);
858 NsanThread
*main_thread
= NsanThread::Create(nullptr, nullptr);
859 SetCurrentThread(main_thread
);
863 if (flags().print_stats_on_exit
)
866 nsan_init_is_running
= false;
867 nsan_initialized
= true;