Path: blob/main/contrib/llvm-project/compiler-rt/lib/nsan/nsan.h
35233 views
//===-- nsan.h -------------------------------------------------*- C++ -*-===//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// This file is a part of NumericalStabilitySanitizer.9//10// Private NSan header.11//===----------------------------------------------------------------------===//1213#ifndef NSAN_H14#define NSAN_H1516#include "sanitizer_common/sanitizer_internal_defs.h"1718using __sanitizer::sptr;19using __sanitizer::u16;20using __sanitizer::u8;21using __sanitizer::uptr;2223#include "nsan_platform.h"2425#include <assert.h>26#include <float.h>27#include <limits.h>28#include <math.h>29#include <stdio.h>3031// Private nsan interface. Used e.g. by interceptors.32extern "C" {3334void __nsan_init();3536// This marks the shadow type of the given block of application memory as37// unknown.38// printf-free (see comment in nsan_interceptors.cc).39void __nsan_set_value_unknown(const u8 *addr, uptr size);4041// Copies annotations in the shadow memory for a block of application memory to42// a new address. This function is used together with memory-copying functions43// in application memory, e.g. the instrumentation inserts44// `__nsan_copy_values(dest, src, size)` after builtin calls to45// `memcpy(dest, src, size)`. Intercepted memcpy calls also call this function.46// printf-free (see comment in nsan_interceptors.cc).47void __nsan_copy_values(const u8 *daddr, const u8 *saddr, uptr size);4849SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *50__nsan_default_options();51}5253namespace __nsan {5455extern bool nsan_initialized;56extern bool nsan_init_is_running;5758void InitializeInterceptors();59void InitializeMallocInterceptors();6061// See notes in nsan_platform.62// printf-free (see comment in nsan_interceptors.cc).63inline u8 *GetShadowAddrFor(u8 *Ptr) {64uptr AppOffset = ((uptr)Ptr) & ShadowMask();65return (u8 *)(AppOffset * kShadowScale + ShadowAddr());66}6768// printf-free (see comment in nsan_interceptors.cc).69inline const u8 *GetShadowAddrFor(const u8 *Ptr) {70return GetShadowAddrFor(const_cast<u8 *>(Ptr));71}7273// printf-free (see comment in nsan_interceptors.cc).74inline u8 *GetShadowTypeAddrFor(u8 *Ptr) {75uptr AppOffset = ((uptr)Ptr) & ShadowMask();76return (u8 *)(AppOffset + TypesAddr());77}7879// printf-free (see comment in nsan_interceptors.cc).80inline const u8 *GetShadowTypeAddrFor(const u8 *Ptr) {81return GetShadowTypeAddrFor(const_cast<u8 *>(Ptr));82}8384// Information about value types and their shadow counterparts.85template <typename FT> struct FTInfo {};86template <> struct FTInfo<float> {87using orig_type = float;88using orig_bits_type = __sanitizer::u32;89using mantissa_bits_type = __sanitizer::u32;90using shadow_type = double;91static const char *kCppTypeName;92static constexpr unsigned kMantissaBits = 23;93static constexpr int kExponentBits = 8;94static constexpr int kExponentBias = 127;95static constexpr int kValueType = kFloatValueType;96static constexpr char kTypePattern[sizeof(float)] = {97static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)),98static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)),99static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)),100static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)),101};102static constexpr const float kEpsilon = FLT_EPSILON;103};104template <> struct FTInfo<double> {105using orig_type = double;106using orig_bits_type = __sanitizer::u64;107using mantissa_bits_type = __sanitizer::u64;108using shadow_type = __float128;109static const char *kCppTypeName;110static constexpr unsigned kMantissaBits = 52;111static constexpr int kExponentBits = 11;112static constexpr int kExponentBias = 1023;113static constexpr int kValueType = kDoubleValueType;114static constexpr char kTypePattern[sizeof(double)] = {115static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)),116static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)),117static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)),118static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)),119static_cast<unsigned char>(kValueType | (4 << kValueSizeSizeBits)),120static_cast<unsigned char>(kValueType | (5 << kValueSizeSizeBits)),121static_cast<unsigned char>(kValueType | (6 << kValueSizeSizeBits)),122static_cast<unsigned char>(kValueType | (7 << kValueSizeSizeBits)),123};124static constexpr const float kEpsilon = DBL_EPSILON;125};126template <> struct FTInfo<long double> {127using orig_type = long double;128using mantissa_bits_type = __sanitizer::u64;129using shadow_type = __float128;130static const char *kCppTypeName;131static constexpr unsigned kMantissaBits = 63;132static constexpr int kExponentBits = 15;133static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1;134static constexpr int kValueType = kFp80ValueType;135static constexpr char kTypePattern[sizeof(long double)] = {136static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)),137static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)),138static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)),139static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)),140static_cast<unsigned char>(kValueType | (4 << kValueSizeSizeBits)),141static_cast<unsigned char>(kValueType | (5 << kValueSizeSizeBits)),142static_cast<unsigned char>(kValueType | (6 << kValueSizeSizeBits)),143static_cast<unsigned char>(kValueType | (7 << kValueSizeSizeBits)),144static_cast<unsigned char>(kValueType | (8 << kValueSizeSizeBits)),145static_cast<unsigned char>(kValueType | (9 << kValueSizeSizeBits)),146static_cast<unsigned char>(kValueType | (10 << kValueSizeSizeBits)),147static_cast<unsigned char>(kValueType | (11 << kValueSizeSizeBits)),148static_cast<unsigned char>(kValueType | (12 << kValueSizeSizeBits)),149static_cast<unsigned char>(kValueType | (13 << kValueSizeSizeBits)),150static_cast<unsigned char>(kValueType | (14 << kValueSizeSizeBits)),151static_cast<unsigned char>(kValueType | (15 << kValueSizeSizeBits)),152};153static constexpr const float kEpsilon = LDBL_EPSILON;154};155156template <> struct FTInfo<__float128> {157using orig_type = __float128;158using orig_bits_type = __uint128_t;159using mantissa_bits_type = __uint128_t;160static const char *kCppTypeName;161static constexpr unsigned kMantissaBits = 112;162static constexpr int kExponentBits = 15;163static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1;164};165166constexpr double kMaxULPDiff = INFINITY;167168// Helper for getULPDiff that works on bit representations.169template <typename BT> double GetULPDiffBits(BT v1_bits, BT v2_bits) {170// If the integer representations of two same-sign floats are subtracted then171// the absolute value of the result is equal to one plus the number of172// representable floats between them.173return v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits;174}175176// Returns the the number of floating point values between v1 and v2, capped to177// u64max. Return 0 for (-0.0,0.0).178template <typename FT> double GetULPDiff(FT v1, FT v2) {179if (v1 == v2) {180return 0; // Typically, -0.0 and 0.0181}182using BT = typename FTInfo<FT>::orig_bits_type;183static_assert(sizeof(FT) == sizeof(BT), "not implemented");184static_assert(sizeof(BT) <= 64, "not implemented");185BT v1_bits;186__builtin_memcpy(&v1_bits, &v1, sizeof(BT));187BT v2_bits;188__builtin_memcpy(&v2_bits, &v2, sizeof(BT));189// Check whether the signs differ. IEEE-754 float types always store the sign190// in the most significant bit. NaNs and infinities are handled by the calling191// code.192constexpr BT kSignMask = BT{1} << (CHAR_BIT * sizeof(BT) - 1);193if ((v1_bits ^ v2_bits) & kSignMask) {194// Signs differ. We can get the ULPs as `getULPDiff(negative_number, -0.0)195// + getULPDiff(0.0, positive_number)`.196if (v1_bits & kSignMask) {197return GetULPDiffBits<BT>(v1_bits, kSignMask) +198GetULPDiffBits<BT>(0, v2_bits);199} else {200return GetULPDiffBits<BT>(v2_bits, kSignMask) +201GetULPDiffBits<BT>(0, v1_bits);202}203}204return GetULPDiffBits(v1_bits, v2_bits);205}206207// FIXME: This needs mor work: Because there is no 80-bit integer type, we have208// to go through __uint128_t. Therefore the assumptions about the sign bit do209// not hold.210template <> inline double GetULPDiff(long double v1, long double v2) {211using BT = __uint128_t;212BT v1_bits = 0;213__builtin_memcpy(&v1_bits, &v1, sizeof(long double));214BT v2_bits = 0;215__builtin_memcpy(&v2_bits, &v2, sizeof(long double));216if ((v1_bits ^ v2_bits) & (BT{1} << (CHAR_BIT * sizeof(BT) - 1)))217return v1 == v2 ? __sanitizer::u64{0} : kMaxULPDiff; // Signs differ.218// If the integer representations of two same-sign floats are subtracted then219// the absolute value of the result is equal to one plus the number of220// representable floats between them.221BT diff = v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits;222return diff >= kMaxULPDiff ? kMaxULPDiff : diff;223}224225} // end namespace __nsan226227#endif // NSAN_H228229230