llvm/compiler-rt/lib/nsan/nsan.cpp

//===-- nsan.cc -----------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// NumericalStabilitySanitizer runtime.
//
// This implements:
//  - The public nsan interface (include/sanitizer/nsan_interface.h).
//  - The private nsan interface (./nsan.h).
//  - The internal instrumentation interface. These are function emitted by the
//    instrumentation pass:
//        * __nsan_get_shadow_ptr_for_{float,double,longdouble}_load
//          These return the shadow memory pointer for loading the shadow value,
//          after checking that the types are consistent. If the types are not
//          consistent, returns nullptr.
//        * __nsan_get_shadow_ptr_for_{float,double,longdouble}_store
//          Sets the shadow types appropriately and returns the shadow memory
//          pointer for storing the shadow value.
//        * __nsan_internal_check_{float,double,long double}_{f,d,l} checks the
//          accuracy of a value against its shadow and emits a warning depending
//          on the runtime configuration. The middle part indicates the type of
//          the application value, the suffix (f,d,l) indicates the type of the
//          shadow, and depends on the instrumentation configuration.
//        * __nsan_fcmp_fail_* emits a warning for a fcmp instruction whose
//          corresponding shadow fcmp result differs.
//
//===----------------------------------------------------------------------===//

#include "nsan.h"
#include "nsan_flags.h"
#include "nsan_stats.h"
#include "nsan_suppressions.h"
#include "nsan_thread.h"

#include <assert.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_symbolizer.h"

usingnamespace__sanitizer;
usingnamespace__nsan;

constexpr int kMaxVectorWidth =;

// When copying application memory, we also copy its shadow and shadow type.
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_copy_values(const void *daddr, const void *saddr, uptr size) {}

#define NSAN_COPY_VALUES_N(N)

NSAN_COPY_VALUES_N()
NSAN_COPY_VALUES_N()
NSAN_COPY_VALUES_N()

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_set_value_unknown(const void *addr, uptr size) {}

#define NSAN_SET_VALUE_UNKNOWN_N(N)

NSAN_SET_VALUE_UNKNOWN_N()
NSAN_SET_VALUE_UNKNOWN_N()
NSAN_SET_VALUE_UNKNOWN_N()

const char *FTInfo<float>::kCppTypeName =;
const char *FTInfo<double>::kCppTypeName =;
const char *FTInfo<long double>::kCppTypeName =;
const char *FTInfo<__float128>::kCppTypeName =;

const char FTInfo<float>::kTypePattern[sizeof(float)];
const char FTInfo<double>::kTypePattern[sizeof(double)];
const char FTInfo<long double>::kTypePattern[sizeof(long double)];

// Helper for __nsan_dump_shadow_mem: Reads the value at address `ptr`,
// identified by its type id.
template <typename ShadowFT>
static __float128 ReadShadowInternal(const u8 *ptr) {}

static __float128 ReadShadow(const u8 *ptr, const char ShadowTypeId) {}

namespace {
class Decorator : public __sanitizer::SanitizerCommonDecorator {};

// Workaround for the fact that Printf() does not support floats.
struct PrintBuffer {};
template <typename FT> struct FTPrinter {};

template <> struct FTPrinter<double> {};

template <> struct FTPrinter<float> : FTPrinter<double> {};

template <> struct FTPrinter<long double> {};

// FIXME: print with full precision.
template <> struct FTPrinter<__float128> : FTPrinter<long double> {};

// This is a template so that there are no implicit conversions.
template <typename FT> inline FT ftAbs(FT v);

template <> inline long double ftAbs(long double v) {}
template <> inline double ftAbs(double v) {}

// We don't care about nans.
// std::abs(__float128) code is suboptimal and generates a function call to
// __getf2().
template <typename FT> inline FT ftAbs(FT v) {}

template <typename FT1, typename FT2, bool Enable> struct LargestFTImpl {};

LargestFTImpl<FT1, FT2, true>;

LargestFT;

template <typename T> T max(T a, T b) {}

} // end anonymous namespace

void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
                                                 void *context,
                                                 bool request_fast,
                                                 u32 max_depth) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_print_accumulated_stats() {}

static void NsanAtexit() {}

// The next three functions return a pointer for storing a shadow value for `n`
// values, after setting the shadow types. We return the pointer instead of
// storing ourselves because it avoids having to rely on the calling convention
// around long double being the same for nsan and the target application.
// We have to have 3 versions because we need to know which type we are storing
// since we are setting the type shadow memory.
template <typename FT> static u8 *getShadowPtrForStore(u8 *store_addr, uptr n) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_get_shadow_ptr_for_float_store(u8 *store_addr, uptr n) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_get_shadow_ptr_for_double_store(u8 *store_addr, uptr n) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_get_shadow_ptr_for_longdouble_store(u8 *store_addr, uptr n) {}

template <typename FT> static bool IsValidShadowType(const u8 *shadow_type) {}

template <int kSize, typename T> static bool IsZero(const T *ptr) {}

template <typename FT> static bool IsUnknownShadowType(const u8 *shadow_type) {}

// The three folowing functions check that the address stores a complete
// shadow value of the given type and return a pointer for loading.
// They return nullptr if the type of the value is unknown or incomplete.
template <typename FT>
static const u8 *getShadowPtrForLoad(const u8 *load_addr, uptr n) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
__nsan_get_shadow_ptr_for_float_load(const u8 *load_addr, uptr n) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
__nsan_get_shadow_ptr_for_double_load(const u8 *load_addr, uptr n) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE const u8 *
__nsan_get_shadow_ptr_for_longdouble_load(const u8 *load_addr, uptr n) {}

// Returns the raw shadow pointer. The returned pointer should be considered
// opaque.
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_internal_get_raw_shadow_ptr(const u8 *addr) {}

// Returns the raw shadow type pointer. The returned pointer should be
// considered opaque.
extern "C" SANITIZER_INTERFACE_ATTRIBUTE u8 *
__nsan_internal_get_raw_shadow_type_ptr(const u8 *addr) {}

static ValueType getValueType(u8 c) {}

static int getValuePos(u8 c) {}

// Checks the consistency of the value types at the given type pointer.
// If the value is inconsistent, returns ValueType::kUnknown. Else, return the
// consistent type.
template <typename FT>
static bool checkValueConsistency(const u8 *shadow_type) {}

// The instrumentation automatically appends `shadow_value_type_ids`, see
// maybeAddSuffixForNsanInterface.
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_dump_shadow_mem(const u8 *addr, size_t size_bytes, size_t bytes_per_line,
                       size_t shadow_value_type_ids) {}

alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
    thread_local uptr __nsan_shadow_ret_tag =;

alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
    thread_local char __nsan_shadow_ret_ptr[kMaxVectorWidth *
                                            sizeof(__float128)];

alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
    thread_local uptr __nsan_shadow_args_tag =;

// Maximum number of args. This should be enough for anyone (tm). An alternate
// scheme is to have the generated code create an alloca and make
// __nsan_shadow_args_ptr point ot the alloca.
constexpr const int kMaxNumArgs =;
alignas(64) SANITIZER_INTERFACE_ATTRIBUTE
    thread_local char __nsan_shadow_args_ptr[kMaxVectorWidth * kMaxNumArgs *
                                             sizeof(__float128)];

enum ContinuationType {};

// Checks the consistency between application and shadow value. Returns true
// when the instrumented code should resume computations from the original value
// rather than the shadow value. This prevents one error to propagate to all
// subsequent operations. This behaviour is tunable with flags.
template <typename FT, typename ShadowFT>
int32_t checkFT(const FT value, ShadowFT Shadow, CheckTypeT CheckType,
                uptr CheckArg) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_float_d(
    float value, double shadow, int32_t check_type, uptr check_arg) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_double_l(
    double value, long double shadow, int32_t check_type, uptr check_arg) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t __nsan_internal_check_double_q(
    double value, __float128 shadow, int32_t check_type, uptr check_arg) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE int32_t
__nsan_internal_check_longdouble_q(long double value, __float128 shadow,
                                   int32_t check_type, uptr check_arg) {}

static const char *GetTruthValueName(bool v) {}

// This uses the same values as CmpInst::Predicate.
static const char *GetPredicateName(int v) {}

template <typename FT, typename ShadowFT>
void fCmpFailFT(const FT Lhs, const FT Rhs, ShadowFT LhsShadow,
                ShadowFT RhsShadow, int Predicate, bool result,
                bool ShadowResult) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_fcmp_fail_float_d(float lhs, float rhs, double lhs_shadow,
                         double rhs_shadow, int predicate, bool result,
                         bool shadow_result) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_fcmp_fail_double_q(double lhs, double rhs, __float128 lhs_shadow,
                          __float128 rhs_shadow, int predicate, bool result,
                          bool shadow_result) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_fcmp_fail_double_l(double lhs, double rhs, long double lhs_shadow,
                          long double rhs_shadow, int predicate, bool result,
                          bool shadow_result) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_fcmp_fail_longdouble_q(long double lhs, long double rhs,
                              __float128 lhs_shadow, __float128 rhs_shadow,
                              int predicate, bool result, bool shadow_result) {}

template <typename FT> void checkFTFromShadowStack(const FT value) {}

// FIXME: Add suffixes and let the instrumentation pass automatically add
// suffixes.
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_check_float(float value) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_check_double(double value) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_check_longdouble(long double value) {}

template <typename FT> static void dumpFTFromShadowStack(const FT value) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_float(float value) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_double(double value) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__nsan_dump_longdouble(long double value) {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_ret() {}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_dump_shadow_args() {}

bool __nsan::nsan_initialized;
bool __nsan::nsan_init_is_running;

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __nsan_init() {}