Path: blob/main/contrib/llvm-project/compiler-rt/lib/nsan/nsan.cpp
35233 views
//===-- nsan.cc -----------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// NumericalStabilitySanitizer runtime.9//10// This implements:11// - The public nsan interface (include/sanitizer/nsan_interface.h).12// - The private nsan interface (./nsan.h).13// - The internal instrumentation interface. These are function emitted by the14// instrumentation pass:15// * __nsan_get_shadow_ptr_for_{float,double,longdouble}_load16// These return the shadow memory pointer for loading the shadow value,17// after checking that the types are consistent. If the types are not18// consistent, returns nullptr.19// * __nsan_get_shadow_ptr_for_{float,double,longdouble}_store20// Sets the shadow types appropriately and returns the shadow memory21// pointer for storing the shadow value.22// * __nsan_internal_check_{float,double,long double}_{f,d,l} checks the23// accuracy of a value against its shadow and emits a warning depending24// on the runtime configuration. The middle part indicates the type of25// the application value, the suffix (f,d,l) indicates the type of the26// shadow, and depends on the instrumentation configuration.27// * __nsan_fcmp_fail_* emits a warning for an fcmp instruction whose28// corresponding shadow fcmp result differs.29//30//===----------------------------------------------------------------------===//3132#include <assert.h>33#include <math.h>34#include <stdint.h>35#include <stdio.h>36#include <stdlib.h>3738#include "sanitizer_common/sanitizer_atomic.h"39#include "sanitizer_common/sanitizer_common.h"40#include "sanitizer_common/sanitizer_libc.h"41#include "sanitizer_common/sanitizer_report_decorator.h"42#include "sanitizer_common/sanitizer_stacktrace.h"43#include "sanitizer_common/sanitizer_symbolizer.h"4445#include "nsan/nsan.h"46#include "nsan/nsan_flags.h"47#include "nsan/nsan_stats.h"48#include "nsan/nsan_suppressions.h"4950using namespace __sanitizer;51using namespace __nsan;5253constexpr int kMaxVectorWidth = 8;5455// When copying application memory, we also copy its shadow and shadow type.56// FIXME: We could provide fixed-size versions that would nicely57// vectorize for known sizes.58extern "C" SANITIZER_INTERFACE_ATTRIBUTE void59__nsan_copy_values(const u8 *daddr, const u8 *saddr, uptr size) {60internal_memmove((void *)GetShadowTypeAddrFor(daddr),61GetShadowTypeAddrFor(saddr), size);62internal_memmove((void *)GetShadowAddrFor(daddr), GetShadowAddrFor(saddr),63size * kShadowScale);64}6566// FIXME: We could provide fixed-size versions that would nicely67// vectorize for known sizes.68extern "C" SANITIZER_INTERFACE_ATTRIBUTE void69__nsan_set_value_unknown(const u8 *addr, uptr size) {70internal_memset((void *)GetShadowTypeAddrFor(addr), 0, size);71}727374const char *FTInfo<float>::kCppTypeName = "float";75const char *FTInfo<double>::kCppTypeName = "double";76const char *FTInfo<long double>::kCppTypeName = "long double";77const char *FTInfo<__float128>::kCppTypeName = "__float128";7879const char FTInfo<float>::kTypePattern[sizeof(float)];80const char FTInfo<double>::kTypePattern[sizeof(double)];81const char FTInfo<long double>::kTypePattern[sizeof(long double)];8283// Helper for __nsan_dump_shadow_mem: Reads the value at address `ptr`,84// identified by its type id.85template <typename ShadowFT>86static __float128 ReadShadowInternal(const u8 *ptr) {87ShadowFT Shadow;88__builtin_memcpy(&Shadow, ptr, sizeof(Shadow));89return Shadow;90}9192static __float128 ReadShadow(const u8 *ptr, const char ShadowTypeId) {93switch (ShadowTypeId) {94case 'd':95return ReadShadowInternal<double>(ptr);96case 'l':97return ReadShadowInternal<long double>(ptr);98case 'q':99return ReadShadowInternal<__float128>(ptr);100default:101return 0.0;102}103}104105namespace {106class Decorator : public __sanitizer::SanitizerCommonDecorator {107public:108Decorator() : SanitizerCommonDecorator() {}109const char *Warning() { return Red(); }110const char *Name() { return Green(); }111const char *End() { return Default(); }112};113114// Workaround for the fact that Printf() does not support floats.115struct PrintBuffer {116char Buffer[64];117};118template <typename FT> struct FTPrinter {};119120template <> struct FTPrinter<double> {121static PrintBuffer dec(double value) {122PrintBuffer result;123snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20f", value);124return result;125}126static PrintBuffer hex(double value) {127PrintBuffer result;128snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20a", value);129return result;130}131};132133template <> struct FTPrinter<float> : FTPrinter<double> {};134135template <> struct FTPrinter<long double> {136static PrintBuffer dec(long double value) {137PrintBuffer result;138snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20Lf", value);139return result;140}141static PrintBuffer hex(long double value) {142PrintBuffer result;143snprintf(result.Buffer, sizeof(result.Buffer) - 1, "%.20La", value);144return result;145}146};147148// FIXME: print with full precision.149template <> struct FTPrinter<__float128> : FTPrinter<long double> {};150151// This is a template so that there are no implicit conversions.152template <typename FT> inline FT ftAbs(FT v);153154template <> inline long double ftAbs(long double v) { return fabsl(v); }155template <> inline double ftAbs(double v) { return fabs(v); }156157// We don't care about nans.158// std::abs(__float128) code is suboptimal and generates a function call to159// __getf2().160template <typename FT> inline FT ftAbs(FT v) { return v >= FT{0} ? v : -v; }161162template <typename FT1, typename FT2, bool Enable> struct LargestFTImpl {163using type = FT2;164};165166template <typename FT1, typename FT2> struct LargestFTImpl<FT1, FT2, true> {167using type = FT1;168};169170template <typename FT1, typename FT2>171using LargestFT =172typename LargestFTImpl<FT1, FT2, (sizeof(FT1) > sizeof(FT2))>::type;173174template <typename T> T max(T a, T b) { return a < b ? b : a; }175176} // end anonymous namespace177178void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,179void *context,180bool request_fast,181u32 max_depth) {182using namespace __nsan;183return Unwind(max_depth, pc, bp, context, 0, 0, false);184}185186extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_print_accumulated_stats() {187if (nsan_stats)188nsan_stats->Print();189}190191static void NsanAtexit() {192Printf("Numerical Sanitizer exit stats:\n");193__nsan_print_accumulated_stats();194nsan_stats = nullptr;195}196197// The next three functions return a pointer for storing a shadow value for `n`198// values, after setting the shadow types. We return the pointer instead of199// storing ourselves because it avoids having to rely on the calling convention200// around long double being the same for nsan and the target application.201// We have to have 3 versions because we need to know which type we are storing202// since we are setting the type shadow memory.203template <typename FT> static u8 *getShadowPtrForStore(u8 *store_addr, uptr n) {204unsigned char *shadow_type = GetShadowTypeAddrFor(store_addr);205for (uptr i = 0; i < n; ++i) {206__builtin_memcpy(shadow_type + i * sizeof(FT), FTInfo<FT>::kTypePattern,207sizeof(FTInfo<FT>::kTypePattern));208}209return GetShadowAddrFor(store_addr);210}211212extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *213__nsan_get_shadow_ptr_for_float_store(u8 *store_addr, uptr n) {214return getShadowPtrForStore<float>(store_addr, n);215}216217extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *218__nsan_get_shadow_ptr_for_double_store(u8 *store_addr, uptr n) {219return getShadowPtrForStore<double>(store_addr, n);220}221222extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *223__nsan_get_shadow_ptr_for_longdouble_store(u8 *store_addr, uptr n) {224return getShadowPtrForStore<long double>(store_addr, n);225}226227template <typename FT> static bool IsValidShadowType(const u8 *shadow_type) {228return __builtin_memcmp(shadow_type, FTInfo<FT>::kTypePattern, sizeof(FT)) ==2290;230}231232template <int kSize, typename T> static bool IsZero(const T *ptr) {233constexpr const char kZeros[kSize] = {}; // Zero initialized.234return __builtin_memcmp(ptr, kZeros, kSize) == 0;235}236237template <typename FT> static bool IsUnknownShadowType(const u8 *shadow_type) {238return IsZero<sizeof(FTInfo<FT>::kTypePattern)>(shadow_type);239}240241// The three folowing functions check that the address stores a complete242// shadow value of the given type and return a pointer for loading.243// They return nullptr if the type of the value is unknown or incomplete.244template <typename FT>245static const u8 *getShadowPtrForLoad(const u8 *load_addr, uptr n) {246const u8 *const shadow_type = GetShadowTypeAddrFor(load_addr);247for (uptr i = 0; i < n; ++i) {248if (!IsValidShadowType<FT>(shadow_type + i * sizeof(FT))) {249// If loadtracking stats are enabled, log loads with invalid types250// (tampered with through type punning).251if (flags().enable_loadtracking_stats) {252if (IsUnknownShadowType<FT>(shadow_type + i * sizeof(FT))) {253// Warn only if the value is non-zero. Zero is special because254// applications typically initialize large buffers to zero in an255// untyped way.256if (!IsZero<sizeof(FT)>(load_addr)) {257GET_CALLER_PC_BP;258nsan_stats->AddUnknownLoadTrackingEvent(pc, bp);259}260} else {261GET_CALLER_PC_BP;262nsan_stats->AddInvalidLoadTrackingEvent(pc, bp);263}264}265return nullptr;266}267}268return GetShadowAddrFor(load_addr);269}270271extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *272__nsan_get_shadow_ptr_for_float_load(const u8 *load_addr, uptr n) {273return getShadowPtrForLoad<float>(load_addr, n);274}275276extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *277__nsan_get_shadow_ptr_for_double_load(const u8 *load_addr, uptr n) {278return getShadowPtrForLoad<double>(load_addr, n);279}280281extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *282__nsan_get_shadow_ptr_for_longdouble_load(const u8 *load_addr, uptr n) {283return getShadowPtrForLoad<long double>(load_addr, n);284}285286// Returns the raw shadow pointer. The returned pointer should be considered287// opaque.288extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *289__nsan_internal_get_raw_shadow_ptr(const u8 *addr) {290return GetShadowAddrFor(const_cast<u8 *>(addr));291}292293// Returns the raw shadow type pointer. The returned pointer should be294// considered opaque.295extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *296__nsan_internal_get_raw_shadow_type_ptr(const u8 *addr) {297return reinterpret_cast<u8 *>(GetShadowTypeAddrFor(const_cast<u8 *>(addr)));298}299300static ValueType getValueType(u8 c) { return static_cast<ValueType>(c & 0x3); }301302static int getValuePos(u8 c) { return c >> kValueSizeSizeBits; }303304// Checks the consistency of the value types at the given type pointer.305// If the value is inconsistent, returns ValueType::kUnknown. Else, return the306// consistent type.307template <typename FT>308static bool checkValueConsistency(const u8 *shadow_type) {309const int pos = getValuePos(*shadow_type);310// Check that all bytes from the start of the value are ordered.311for (uptr i = 0; i < sizeof(FT); ++i) {312const u8 T = *(shadow_type - pos + i);313if (!(getValueType(T) == FTInfo<FT>::kValueType && getValuePos(T) == i))314return false;315}316return true;317}318319// The instrumentation automatically appends `shadow_value_type_ids`, see320// maybeAddSuffixForNsanInterface.321extern "C" SANITIZER_INTERFACE_ATTRIBUTE void322__nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line,323size_t shadow_value_type_ids) {324const u8 *const shadow_type = GetShadowTypeAddrFor(addr);325const u8 *const shadow = GetShadowAddrFor(addr);326327constexpr int kMaxNumDecodedValues = 16;328__float128 decoded_values[kMaxNumDecodedValues];329int num_decoded_values = 0;330if (bytes_per_line > 4 * kMaxNumDecodedValues)331bytes_per_line = 4 * kMaxNumDecodedValues;332333// We keep track of the current type and position as we go.334ValueType LastValueTy = kUnknownValueType;335int LastPos = -1;336size_t Offset = 0;337for (size_t R = 0; R < (size_bytes + bytes_per_line - 1) / bytes_per_line;338++R) {339printf("%p: ", (void *)(addr + R * bytes_per_line));340for (size_t C = 0; C < bytes_per_line && Offset < size_bytes; ++C) {341const ValueType ValueTy = getValueType(shadow_type[Offset]);342const int pos = getValuePos(shadow_type[Offset]);343if (ValueTy == LastValueTy && pos == LastPos + 1) {344++LastPos;345} else {346LastValueTy = ValueTy;347LastPos = pos == 0 ? 0 : -1;348}349350switch (ValueTy) {351case kUnknownValueType:352printf("__ ");353break;354case kFloatValueType:355printf("f%x ", pos);356if (LastPos == sizeof(float) - 1) {357decoded_values[num_decoded_values] =358ReadShadow(shadow + kShadowScale * (Offset + 1 - sizeof(float)),359static_cast<char>(shadow_value_type_ids & 0xff));360++num_decoded_values;361}362break;363case kDoubleValueType:364printf("d%x ", pos);365if (LastPos == sizeof(double) - 1) {366decoded_values[num_decoded_values] = ReadShadow(367shadow + kShadowScale * (Offset + 1 - sizeof(double)),368static_cast<char>((shadow_value_type_ids >> 8) & 0xff));369++num_decoded_values;370}371break;372case kFp80ValueType:373printf("l%x ", pos);374if (LastPos == sizeof(long double) - 1) {375decoded_values[num_decoded_values] = ReadShadow(376shadow + kShadowScale * (Offset + 1 - sizeof(long double)),377static_cast<char>((shadow_value_type_ids >> 16) & 0xff));378++num_decoded_values;379}380break;381}382++Offset;383}384for (int i = 0; i < num_decoded_values; ++i) {385printf(" (%s)", FTPrinter<__float128>::dec(decoded_values[i]).Buffer);386}387num_decoded_values = 0;388printf("\n");389}390}391392alignas(16) SANITIZER_INTERFACE_ATTRIBUTE393thread_local uptr __nsan_shadow_ret_tag = 0;394395alignas(16) SANITIZER_INTERFACE_ATTRIBUTE396thread_local char __nsan_shadow_ret_ptr[kMaxVectorWidth *397sizeof(__float128)];398399alignas(16) SANITIZER_INTERFACE_ATTRIBUTE400thread_local uptr __nsan_shadow_args_tag = 0;401402// Maximum number of args. This should be enough for anyone (tm). An alternate403// scheme is to have the generated code create an alloca and make404// __nsan_shadow_args_ptr point ot the alloca.405constexpr const int kMaxNumArgs = 128;406alignas(16) SANITIZER_INTERFACE_ATTRIBUTE407thread_local char __nsan_shadow_args_ptr[kMaxVectorWidth * kMaxNumArgs *408sizeof(__float128)];409410enum ContinuationType { // Keep in sync with instrumentation pass.411kContinueWithShadow = 0,412kResumeFromValue = 1,413};414415// Checks the consistency between application and shadow value. Returns true416// when the instrumented code should resume computations from the original value417// rather than the shadow value. This prevents one error to propagate to all418// subsequent operations. This behaviour is tunable with flags.419template <typename FT, typename ShadowFT>420int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,421uptr CheckArg) {422// We do all comparisons in the InternalFT domain, which is the largest FT423// type.424using InternalFT = LargestFT<FT, ShadowFT>;425const InternalFT check_value = value;426const InternalFT check_shadow = Shadow;427428// See this article for an interesting discussion of how to compare floats:429// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/430static constexpr const FT Eps = FTInfo<FT>::kEpsilon;431432const InternalFT abs_err = ftAbs(check_value - check_shadow);433434if (flags().enable_check_stats) {435GET_CALLER_PC_BP;436// We are re-computing `largest` here because this is a cold branch, and we437// want to avoid having to move the computation of `largest` before the438// absolute value check when this branch is not taken.439const InternalFT largest = max(ftAbs(check_value), ftAbs(check_shadow));440nsan_stats->AddCheck(CheckType, pc, bp, abs_err / largest);441}442443// Note: writing the comparison that way ensures that when `abs_err` is Nan444// (value and shadow are inf or -inf), we pass the test.445if (!(abs_err >= flags().cached_absolute_error_threshold))446return kContinueWithShadow;447448const InternalFT largest = max(ftAbs(check_value), ftAbs(check_shadow));449if (abs_err * (1ull << flags().log2_max_relative_error) <= largest)450return kContinueWithShadow; // No problem here.451452if (!flags().disable_warnings) {453GET_CALLER_PC_BP;454BufferedStackTrace stack;455stack.Unwind(pc, bp, nullptr, false);456if (GetSuppressionForStack(&stack, CheckKind::Consistency)) {457// FIXME: optionally print.458return flags().resume_after_suppression ? kResumeFromValue459: kContinueWithShadow;460}461462Decorator D;463Printf("%s", D.Warning());464// Printf does not support float formatting.465char RelErrBuf[64] = "inf";466if (largest > Eps) {467snprintf(RelErrBuf, sizeof(RelErrBuf) - 1, "%.20Lf%% (2^%.0Lf epsilons)",468static_cast<long double>(100.0 * abs_err / largest),469log2l(static_cast<long double>(abs_err / largest / Eps)));470}471char ulp_err_buf[128] = "";472const double shadow_ulp_diff = GetULPDiff(check_value, check_shadow);473if (shadow_ulp_diff != kMaxULPDiff) {474// This is the ULP diff in the internal domain. The user actually cares475// about that in the original domain.476const double ulp_diff =477shadow_ulp_diff / (u64{1} << (FTInfo<InternalFT>::kMantissaBits -478FTInfo<FT>::kMantissaBits));479snprintf(ulp_err_buf, sizeof(ulp_err_buf) - 1,480"(%.0f ULPs == %.1f digits == %.1f bits)", ulp_diff,481log10(ulp_diff), log2(ulp_diff));482}483Printf("WARNING: NumericalStabilitySanitizer: inconsistent shadow results");484switch (CheckType) {485case CheckTypeT::kUnknown:486case CheckTypeT::kFcmp:487case CheckTypeT::kMaxCheckType:488break;489case CheckTypeT::kRet:490Printf(" while checking return value");491break;492case CheckTypeT::kArg:493Printf(" while checking call argument #%d", static_cast<int>(CheckArg));494break;495case CheckTypeT::kLoad:496Printf(497" while checking load from address 0x%lx. This is due to incorrect "498"shadow memory tracking, typically due to uninstrumented code "499"writing to memory.",500CheckArg);501break;502case CheckTypeT::kStore:503Printf(" while checking store to address 0x%lx", CheckArg);504break;505case CheckTypeT::kInsert:506Printf(" while checking vector insert");507break;508case CheckTypeT::kUser:509Printf(" in user-initiated check");510break;511}512using ValuePrinter = FTPrinter<FT>;513using ShadowPrinter = FTPrinter<ShadowFT>;514Printf("%s", D.Default());515516Printf("\n"517"%-12s precision (native): dec: %s hex: %s\n"518"%-12s precision (shadow): dec: %s hex: %s\n"519"shadow truncated to %-12s: dec: %s hex: %s\n"520"Relative error: %s\n"521"Absolute error: %s\n"522"%s\n",523FTInfo<FT>::kCppTypeName, ValuePrinter::dec(value).Buffer,524ValuePrinter::hex(value).Buffer, FTInfo<ShadowFT>::kCppTypeName,525ShadowPrinter::dec(Shadow).Buffer, ShadowPrinter::hex(Shadow).Buffer,526FTInfo<FT>::kCppTypeName, ValuePrinter::dec(Shadow).Buffer,527ValuePrinter::hex(Shadow).Buffer, RelErrBuf,528ValuePrinter::hex(abs_err).Buffer, ulp_err_buf);529stack.Print();530}531532if (flags().enable_warning_stats) {533GET_CALLER_PC_BP;534nsan_stats->AddWarning(CheckType, pc, bp, abs_err / largest);535}536537if (flags().halt_on_error) {538if (common_flags()->abort_on_error)539Printf("ABORTING\n");540else541Printf("Exiting\n");542Die();543}544return flags().resume_after_warning ? kResumeFromValue : kContinueWithShadow;545}546547extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_float_d(548float value, double shadow, int32_t check_type, uptr check_arg) {549return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);550}551552extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_double_l(553double value, long double shadow, int32_t check_type, uptr check_arg) {554return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);555}556557extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_double_q(558double value, __float128 shadow, int32_t check_type, uptr check_arg) {559return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);560}561562extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t563__nsan_internal_check_longdouble_q(long double value, __float128 shadow,564int32_t check_type, uptr check_arg) {565return checkFT(value, shadow, static_cast<CheckTypeT>(check_type), check_arg);566}567568static const char *GetTruthValueName(bool v) { return v ? "true" : "false"; }569570// This uses the same values as CmpInst::Predicate.571static const char *GetPredicateName(int v) {572switch (v) {573case 0:574return "(false)";575case 1:576return "==";577case 2:578return ">";579case 3:580return ">=";581case 4:582return "<";583case 5:584return "<=";585case 6:586return "!=";587case 7:588return "(ordered)";589case 8:590return "(unordered)";591case 9:592return "==";593case 10:594return ">";595case 11:596return ">=";597case 12:598return "<";599case 13:600return "<=";601case 14:602return "!=";603case 15:604return "(true)";605}606return "??";607}608609template <typename FT, typename ShadowFT>610void fCmpFailFT(const FT Lhs, const FT Rhs, ShadowFT LhsShadow,611ShadowFT RhsShadow, int Predicate, bool result,612bool ShadowResult) {613if (result == ShadowResult) {614// When a vector comparison fails, we fail each element of the comparison615// to simplify instrumented code. Skip elements where the shadow comparison616// gave the same result as the original one.617return;618}619620GET_CALLER_PC_BP;621BufferedStackTrace stack;622stack.Unwind(pc, bp, nullptr, false);623624if (GetSuppressionForStack(&stack, CheckKind::Fcmp)) {625// FIXME: optionally print.626return;627}628629if (flags().enable_warning_stats)630nsan_stats->AddWarning(CheckTypeT::kFcmp, pc, bp, 0.0);631632if (flags().disable_warnings)633return;634635// FIXME: ideally we would print the shadow value as FP128. Right now because636// we truncate to long double we can sometimes see stuff like:637// shadow <value> == <value> (false)638using ValuePrinter = FTPrinter<FT>;639using ShadowPrinter = FTPrinter<ShadowFT>;640Decorator D;641const char *const PredicateName = GetPredicateName(Predicate);642Printf("%s", D.Warning());643Printf("WARNING: NumericalStabilitySanitizer: floating-point comparison "644"results depend on precision\n");645Printf("%s", D.Default());646Printf("%-12s precision dec (native): %s %s %s (%s)\n"647"%-12s precision dec (shadow): %s %s %s (%s)\n"648"%-12s precision hex (native): %s %s %s (%s)\n"649"%-12s precision hex (shadow): %s %s %s (%s)\n"650"%s",651// Native, decimal.652FTInfo<FT>::kCppTypeName, ValuePrinter::dec(Lhs).Buffer, PredicateName,653ValuePrinter::dec(Rhs).Buffer, GetTruthValueName(result),654// Shadow, decimal655FTInfo<ShadowFT>::kCppTypeName, ShadowPrinter::dec(LhsShadow).Buffer,656PredicateName, ShadowPrinter::dec(RhsShadow).Buffer,657GetTruthValueName(ShadowResult),658// Native, hex.659FTInfo<FT>::kCppTypeName, ValuePrinter::hex(Lhs).Buffer, PredicateName,660ValuePrinter::hex(Rhs).Buffer, GetTruthValueName(result),661// Shadow, hex662FTInfo<ShadowFT>::kCppTypeName, ShadowPrinter::hex(LhsShadow).Buffer,663PredicateName, ShadowPrinter::hex(RhsShadow).Buffer,664GetTruthValueName(ShadowResult), D.End());665stack.Print();666if (flags().halt_on_error) {667Printf("Exiting\n");668Die();669}670}671672extern "C" SANITIZER_INTERFACE_ATTRIBUTE void673__nsan_fcmp_fail_float_d(float lhs, float rhs, double lhs_shadow,674double rhs_shadow, int predicate, bool result,675bool shadow_result) {676fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,677shadow_result);678}679680extern "C" SANITIZER_INTERFACE_ATTRIBUTE void681__nsan_fcmp_fail_double_q(double lhs, double rhs, __float128 lhs_shadow,682__float128 rhs_shadow, int predicate, bool result,683bool shadow_result) {684fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,685shadow_result);686}687688extern "C" SANITIZER_INTERFACE_ATTRIBUTE void689__nsan_fcmp_fail_double_l(double lhs, double rhs, long double lhs_shadow,690long double rhs_shadow, int predicate, bool result,691bool shadow_result) {692fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,693shadow_result);694}695696extern "C" SANITIZER_INTERFACE_ATTRIBUTE void697__nsan_fcmp_fail_longdouble_q(long double lhs, long double rhs,698__float128 lhs_shadow, __float128 rhs_shadow,699int predicate, bool result, bool shadow_result) {700fCmpFailFT(lhs, rhs, lhs_shadow, rhs_shadow, predicate, result,701shadow_result);702}703704template <typename FT> void checkFTFromShadowStack(const FT value) {705// Get the shadow 2FT value from the shadow stack. Note that706// __nsan_check_{float,double,long double} is a function like any other, so707// the instrumentation will have placed the shadow value on the shadow stack.708using ShadowFT = typename FTInfo<FT>::shadow_type;709ShadowFT Shadow;710__builtin_memcpy(&Shadow, __nsan_shadow_args_ptr, sizeof(ShadowFT));711checkFT(value, Shadow, CheckTypeT::kUser, 0);712}713714// FIXME: Add suffixes and let the instrumentation pass automatically add715// suffixes.716extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_check_float(float value) {717assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_float &&718"__nsan_check_float called from non-instrumented function");719checkFTFromShadowStack(value);720}721722extern "C" SANITIZER_INTERFACE_ATTRIBUTE void723__nsan_check_double(double value) {724assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_double &&725"__nsan_check_double called from non-instrumented function");726checkFTFromShadowStack(value);727}728729extern "C" SANITIZER_INTERFACE_ATTRIBUTE void730__nsan_check_longdouble(long double value) {731assert(__nsan_shadow_args_tag == (uptr)&__nsan_check_longdouble &&732"__nsan_check_longdouble called from non-instrumented function");733checkFTFromShadowStack(value);734}735736template <typename FT> static void dumpFTFromShadowStack(const FT value) {737// Get the shadow 2FT value from the shadow stack. Note that738// __nsan_dump_{float,double,long double} is a function like any other, so739// the instrumentation will have placed the shadow value on the shadow stack.740using ShadowFT = typename FTInfo<FT>::shadow_type;741ShadowFT shadow;742__builtin_memcpy(&shadow, __nsan_shadow_args_ptr, sizeof(ShadowFT));743using ValuePrinter = FTPrinter<FT>;744using ShadowPrinter = FTPrinter<typename FTInfo<FT>::shadow_type>;745printf("value dec:%s hex:%s\n"746"shadow dec:%s hex:%s\n",747ValuePrinter::dec(value).Buffer, ValuePrinter::hex(value).Buffer,748ShadowPrinter::dec(shadow).Buffer, ShadowPrinter::hex(shadow).Buffer);749}750751extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_float(float value) {752assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_float &&753"__nsan_dump_float called from non-instrumented function");754dumpFTFromShadowStack(value);755}756757extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_double(double value) {758assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_double &&759"__nsan_dump_double called from non-instrumented function");760dumpFTFromShadowStack(value);761}762763extern "C" SANITIZER_INTERFACE_ATTRIBUTE void764__nsan_dump_longdouble(long double value) {765assert(__nsan_shadow_args_tag == (uptr)&__nsan_dump_longdouble &&766"__nsan_dump_longdouble called from non-instrumented function");767dumpFTFromShadowStack(value);768}769770extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_ret() {771printf("ret tag: %lx\n", __nsan_shadow_ret_tag);772double v;773__builtin_memcpy(&v, __nsan_shadow_ret_ptr, sizeof(double));774printf("double value: %f\n", v);775// FIXME: float128 value.776}777778extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_args() {779printf("args tag: %lx\n", __nsan_shadow_args_tag);780}781782bool __nsan::nsan_initialized;783bool __nsan::nsan_init_is_running;784785extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_init() {786CHECK(!nsan_init_is_running);787if (nsan_initialized)788return;789nsan_init_is_running = true;790791InitializeFlags();792InitializeSuppressions();793InitializePlatformEarly();794795DisableCoreDumperIfNecessary();796797if (!MmapFixedNoReserve(TypesAddr(), UnusedAddr() - TypesAddr()))798Die();799800InitializeInterceptors();801802InitializeStats();803if (flags().print_stats_on_exit)804Atexit(NsanAtexit);805806nsan_init_is_running = false;807nsan_initialized = true;808}809810811