brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.2 KiB · 08dd027 Raw
233 lines · c
1//===-- nsan.h -------------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of NumericalStabilitySanitizer.10//11// Private NSan header.12//===----------------------------------------------------------------------===//13 14#ifndef NSAN_H15#define NSAN_H16 17#include "sanitizer_common/sanitizer_internal_defs.h"18 19using __sanitizer::sptr;20using __sanitizer::u16;21using __sanitizer::u8;22using __sanitizer::uptr;23 24#include "nsan_platform.h"25 26#include <assert.h>27#include <float.h>28#include <limits.h>29#include <math.h>30#include <stdio.h>31 32// Private nsan interface. Used e.g. by interceptors.33extern "C" {34 35void __nsan_init();36 37// This marks the shadow type of the given block of application memory as38// unknown.39// printf-free (see comment in nsan_interceptors.cc).40void __nsan_set_value_unknown(const void *addr, uptr size);41 42// Copies annotations in the shadow memory for a block of application memory to43// a new address. This function is used together with memory-copying functions44// in application memory, e.g. the instrumentation inserts45// `__nsan_copy_values(dest, src, size)` after builtin calls to46// `memcpy(dest, src, size)`. Intercepted memcpy calls also call this function.47// printf-free (see comment in nsan_interceptors.cc).48void __nsan_copy_values(const void *daddr, const void *saddr, uptr size);49 50SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *51__nsan_default_options();52}53 54// Unwind the stack for fatal error, as the parameter `stack` is55// empty without origins.56#define GET_FATAL_STACK_TRACE_IF_EMPTY(STACK)                                  \57  if (nsan_initialized && (STACK)->size == 0) {                                \58    (STACK)->Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr,  \59                    common_flags()->fast_unwind_on_fatal);                     \60  }61 62namespace __nsan {63 64extern bool nsan_initialized;65extern bool nsan_init_is_running;66 67void InitializeInterceptors();68void InitializeMallocInterceptors();69 70// See notes in nsan_platform.71inline u8 *GetShadowAddrFor(void *ptr) {72  uptr AppOffset = ((uptr)ptr) & ShadowMask();73  return (u8 *)(AppOffset * kShadowScale + ShadowAddr());74}75 76inline u8 *GetShadowAddrFor(const void *ptr) {77  return GetShadowAddrFor(const_cast<void *>(ptr));78}79 80inline u8 *GetShadowTypeAddrFor(void *ptr) {81  uptr app_offset = ((uptr)ptr) & ShadowMask();82  return (u8 *)(app_offset + TypesAddr());83}84 85inline u8 *GetShadowTypeAddrFor(const void *ptr) {86  return GetShadowTypeAddrFor(const_cast<void *>(ptr));87}88 89// Information about value types and their shadow counterparts.90template <typename FT> struct FTInfo {};91template <> struct FTInfo<float> {92  using orig_type = float;93  using orig_bits_type = u32;94  using mantissa_bits_type = u32;95  using shadow_type = double;96  static const char *kCppTypeName;97  static constexpr unsigned kMantissaBits = 23;98  static constexpr int kExponentBits = 8;99  static constexpr int kExponentBias = 127;100  static constexpr int kValueType = kFloatValueType;101  static constexpr char kTypePattern[sizeof(float)] = {102      static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)),103      static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)),104      static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)),105      static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)),106  };107  static constexpr const float kEpsilon = FLT_EPSILON;108};109template <> struct FTInfo<double> {110  using orig_type = double;111  using orig_bits_type = u64;112  using mantissa_bits_type = u64;113  using shadow_type = __float128;114  static const char *kCppTypeName;115  static constexpr unsigned kMantissaBits = 52;116  static constexpr int kExponentBits = 11;117  static constexpr int kExponentBias = 1023;118  static constexpr int kValueType = kDoubleValueType;119  static constexpr char kTypePattern[sizeof(double)] = {120      static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)),121      static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)),122      static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)),123      static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)),124      static_cast<unsigned char>(kValueType | (4 << kValueSizeSizeBits)),125      static_cast<unsigned char>(kValueType | (5 << kValueSizeSizeBits)),126      static_cast<unsigned char>(kValueType | (6 << kValueSizeSizeBits)),127      static_cast<unsigned char>(kValueType | (7 << kValueSizeSizeBits)),128  };129  static constexpr const float kEpsilon = DBL_EPSILON;130};131template <> struct FTInfo<long double> {132  using orig_type = long double;133  using mantissa_bits_type = u64;134  using shadow_type = __float128;135  static const char *kCppTypeName;136  static constexpr unsigned kMantissaBits = 63;137  static constexpr int kExponentBits = 15;138  static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1;139  static constexpr int kValueType = kFp80ValueType;140  static constexpr char kTypePattern[sizeof(long double)] = {141      static_cast<unsigned char>(kValueType | (0 << kValueSizeSizeBits)),142      static_cast<unsigned char>(kValueType | (1 << kValueSizeSizeBits)),143      static_cast<unsigned char>(kValueType | (2 << kValueSizeSizeBits)),144      static_cast<unsigned char>(kValueType | (3 << kValueSizeSizeBits)),145      static_cast<unsigned char>(kValueType | (4 << kValueSizeSizeBits)),146      static_cast<unsigned char>(kValueType | (5 << kValueSizeSizeBits)),147      static_cast<unsigned char>(kValueType | (6 << kValueSizeSizeBits)),148      static_cast<unsigned char>(kValueType | (7 << kValueSizeSizeBits)),149      static_cast<unsigned char>(kValueType | (8 << kValueSizeSizeBits)),150      static_cast<unsigned char>(kValueType | (9 << kValueSizeSizeBits)),151      static_cast<unsigned char>(kValueType | (10 << kValueSizeSizeBits)),152      static_cast<unsigned char>(kValueType | (11 << kValueSizeSizeBits)),153      static_cast<unsigned char>(kValueType | (12 << kValueSizeSizeBits)),154      static_cast<unsigned char>(kValueType | (13 << kValueSizeSizeBits)),155      static_cast<unsigned char>(kValueType | (14 << kValueSizeSizeBits)),156      static_cast<unsigned char>(kValueType | (15 << kValueSizeSizeBits)),157  };158  static constexpr const float kEpsilon = LDBL_EPSILON;159};160 161template <> struct FTInfo<__float128> {162  using orig_type = __float128;163  using orig_bits_type = __uint128_t;164  using mantissa_bits_type = __uint128_t;165  static const char *kCppTypeName;166  static constexpr unsigned kMantissaBits = 112;167  static constexpr int kExponentBits = 15;168  static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1;169};170 171constexpr double kMaxULPDiff = INFINITY;172 173// Helper for getULPDiff that works on bit representations.174template <typename BT> double GetULPDiffBits(BT v1_bits, BT v2_bits) {175  // If the integer representations of two same-sign floats are subtracted then176  // the absolute value of the result is equal to one plus the number of177  // representable floats between them.178  return v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits;179}180 181// Returns the the number of floating point values between v1 and v2, capped to182// u64max. Return 0 for (-0.0,0.0).183template <typename FT> double GetULPDiff(FT v1, FT v2) {184  if (v1 == v2) {185    return 0; // Typically, -0.0 and 0.0186  }187  using BT = typename FTInfo<FT>::orig_bits_type;188  static_assert(sizeof(FT) == sizeof(BT), "not implemented");189  static_assert(sizeof(BT) <= 64, "not implemented");190  BT v1_bits;191  __builtin_memcpy(&v1_bits, &v1, sizeof(BT));192  BT v2_bits;193  __builtin_memcpy(&v2_bits, &v2, sizeof(BT));194  // Check whether the signs differ. IEEE-754 float types always store the sign195  // in the most significant bit. NaNs and infinities are handled by the calling196  // code.197  constexpr BT kSignMask = BT{1} << (CHAR_BIT * sizeof(BT) - 1);198  if ((v1_bits ^ v2_bits) & kSignMask) {199    // Signs differ. We can get the ULPs as `getULPDiff(negative_number, -0.0)200    // + getULPDiff(0.0, positive_number)`.201    if (v1_bits & kSignMask) {202      return GetULPDiffBits<BT>(v1_bits, kSignMask) +203             GetULPDiffBits<BT>(0, v2_bits);204    } else {205      return GetULPDiffBits<BT>(v2_bits, kSignMask) +206             GetULPDiffBits<BT>(0, v1_bits);207    }208  }209  return GetULPDiffBits(v1_bits, v2_bits);210}211 212// FIXME: This needs mor work: Because there is no 80-bit integer type, we have213// to go through __uint128_t. Therefore the assumptions about the sign bit do214// not hold.215template <> inline double GetULPDiff(long double v1, long double v2) {216  using BT = __uint128_t;217  BT v1_bits = 0;218  __builtin_memcpy(&v1_bits, &v1, sizeof(long double));219  BT v2_bits = 0;220  __builtin_memcpy(&v2_bits, &v2, sizeof(long double));221  if ((v1_bits ^ v2_bits) & (BT{1} << (CHAR_BIT * sizeof(BT) - 1)))222    return v1 == v2 ? __sanitizer::u64{0} : kMaxULPDiff; // Signs differ.223  // If the integer representations of two same-sign floats are subtracted then224  // the absolute value of the result is equal to one plus the number of225  // representable floats between them.226  BT diff = v1_bits >= v2_bits ? v1_bits - v2_bits : v2_bits - v1_bits;227  return diff >= kMaxULPDiff ? kMaxULPDiff : diff;228}229 230} // end namespace __nsan231 232#endif // NSAN_H233