#include "llvm/Transforms/Instrumentation/NumericalStabilitySanitizer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/EscapeEnumerator.h"
#include "llvm/Transforms/Utils/Instrumentation.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <cstdint>
usingnamespacellvm;
#define DEBUG_TYPE …
STATISTIC(NumInstrumentedFTLoads,
"Number of instrumented floating-point loads");
STATISTIC(NumInstrumentedFTCalls,
"Number of instrumented floating-point calls");
STATISTIC(NumInstrumentedFTRets,
"Number of instrumented floating-point returns");
STATISTIC(NumInstrumentedFTStores,
"Number of instrumented floating-point stores");
STATISTIC(NumInstrumentedNonFTStores,
"Number of instrumented non floating-point stores");
STATISTIC(
NumInstrumentedNonFTMemcpyStores,
"Number of instrumented non floating-point stores with memcpy semantics");
STATISTIC(NumInstrumentedFCmp, "Number of instrumented fcmps");
static cl::opt<std::string> ClShadowMapping(
"nsan-shadow-type-mapping", cl::init("dqq"),
cl::desc("One shadow type id for each of `float`, `double`, `long double`. "
"`d`,`l`,`q`,`e` mean double, x86_fp80, fp128 (quad) and "
"ppc_fp128 (extended double) respectively. The default is to "
"shadow `float` as `double`, and `double` and `x86_fp80` as "
"`fp128`"),
cl::Hidden);
static cl::opt<bool>
ClInstrumentFCmp("nsan-instrument-fcmp", cl::init(true),
cl::desc("Instrument floating-point comparisons"),
cl::Hidden);
static cl::opt<std::string> ClCheckFunctionsFilter(
"check-functions-filter",
cl::desc("Only emit checks for arguments of functions "
"whose names match the given regular expression"),
cl::value_desc("regex"));
static cl::opt<bool> ClTruncateFCmpEq(
"nsan-truncate-fcmp-eq", cl::init(true),
cl::desc(
"This flag controls the behaviour of fcmp equality comparisons."
"For equality comparisons such as `x == 0.0f`, we can perform the "
"shadow check in the shadow (`x_shadow == 0.0) == (x == 0.0f)`) or app "
" domain (`(trunc(x_shadow) == 0.0f) == (x == 0.0f)`). This helps "
"catch the case when `x_shadow` is accurate enough (and therefore "
"close enough to zero) so that `trunc(x_shadow)` is zero even though "
"both `x` and `x_shadow` are not"),
cl::Hidden);
static cl::opt<bool> ClCheckLoads("nsan-check-loads",
cl::desc("Check floating-point load"),
cl::Hidden);
static cl::opt<bool> ClCheckStores("nsan-check-stores", cl::init(true),
cl::desc("Check floating-point stores"),
cl::Hidden);
static cl::opt<bool> ClCheckRet("nsan-check-ret", cl::init(true),
cl::desc("Check floating-point return values"),
cl::Hidden);
static cl::opt<bool> ClPropagateNonFTConstStoresAsFT(
"nsan-propagate-non-ft-const-stores-as-ft",
cl::desc(
"Propagate non floating-point const stores as floating point values."
"For debugging purposes only"),
cl::Hidden);
constexpr StringLiteral kNsanModuleCtorName("nsan.module_ctor");
constexpr StringLiteral kNsanInitName("__nsan_init");
constexpr int kShadowScale = …;
constexpr int kMaxVectorWidth = …;
constexpr int kMaxNumArgs = …;
constexpr int kMaxShadowTypeSizeBytes = …;
namespace {
class ShadowTypeConfig { … };
template <char NsanTypeId>
class ShadowTypeConfigImpl : public ShadowTypeConfig { … };
class F64ShadowConfig : public ShadowTypeConfigImpl<'d'> { … };
class F80ShadowConfig : public ShadowTypeConfigImpl<'l'> { … };
class F128ShadowConfig : public ShadowTypeConfigImpl<'q'> { … };
class PPC128ShadowConfig : public ShadowTypeConfigImpl<'e'> { … };
std::unique_ptr<ShadowTypeConfig>
ShadowTypeConfig::fromNsanTypeId(const char TypeId) { … }
enum FTValueType { … };
static std::optional<FTValueType> ftValueTypeFromType(Type *FT) { … }
static Type *typeFromFTValueType(FTValueType VT, LLVMContext &Context) { … }
static const char *typeNameFromFTValueType(FTValueType VT) { … }
class MappingConfig { … };
struct MemoryExtents { … };
static MemoryExtents getMemoryExtentsOrDie(Type *FT) { … }
class CheckLoc { … };
class ValueToShadowMap { … };
class NsanMemOpFn { … };
NsanMemOpFn::NsanMemOpFn(Module &M, ArrayRef<StringRef> Sized,
StringRef Fallback, size_t NumArgs) { … }
FunctionCallee NsanMemOpFn::getFunctionFor(uint64_t MemOpSize) const { … }
FunctionCallee NsanMemOpFn::getFallback() const { … }
class NumericalStabilitySanitizer { … };
}
PreservedAnalyses
NumericalStabilitySanitizerPass::run(Module &M, ModuleAnalysisManager &MAM) { … }
static GlobalValue *createThreadLocalGV(const char *Name, Module &M, Type *Ty) { … }
NumericalStabilitySanitizer::NumericalStabilitySanitizer(Module &M)
: … { … }
bool NumericalStabilitySanitizer::addrPointsToConstantData(Value *Addr) { … }
void NumericalStabilitySanitizer::createShadowArguments(
Function &F, const TargetLibraryInfo &TLI, ValueToShadowMap &Map) { … }
static bool shouldCheckArgs(CallBase &CI, const TargetLibraryInfo &TLI,
const std::optional<Regex> &CheckFunctionsFilter) { … }
void NumericalStabilitySanitizer::populateShadowStack(
CallBase &CI, const TargetLibraryInfo &TLI, const ValueToShadowMap &Map) { … }
enum class ContinuationType { … };
Value *NumericalStabilitySanitizer::emitCheckInternal(Value *V, Value *ShadowV,
IRBuilder<> &Builder,
CheckLoc Loc) { … }
Value *NumericalStabilitySanitizer::emitCheck(Value *V, Value *ShadowV,
IRBuilder<> &Builder,
CheckLoc Loc) { … }
void NumericalStabilitySanitizer::emitFCmpCheck(FCmpInst &FCmp,
const ValueToShadowMap &Map) { … }
PHINode *NumericalStabilitySanitizer::maybeCreateShadowPhi(
PHINode &Phi, const TargetLibraryInfo &TLI) { … }
Value *NumericalStabilitySanitizer::handleLoad(LoadInst &Load, Type *VT,
Type *ExtendedVT) { … }
Value *NumericalStabilitySanitizer::handleTrunc(const FPTruncInst &Trunc,
Type *VT, Type *ExtendedVT,
const ValueToShadowMap &Map,
IRBuilder<> &Builder) { … }
Value *NumericalStabilitySanitizer::handleExt(const FPExtInst &Ext, Type *VT,
Type *ExtendedVT,
const ValueToShadowMap &Map,
IRBuilder<> &Builder) { … }
namespace {
struct KnownIntrinsic { … };
}
static FunctionType *makeDoubleDouble(LLVMContext &C) { … }
static FunctionType *makeX86FP80X86FP80(LLVMContext &C) { … }
static FunctionType *makeDoubleDoubleI32(LLVMContext &C) { … }
static FunctionType *makeX86FP80X86FP80I32(LLVMContext &C) { … }
static FunctionType *makeDoubleDoubleDouble(LLVMContext &C) { … }
static FunctionType *makeX86FP80X86FP80X86FP80(LLVMContext &C) { … }
static FunctionType *makeDoubleDoubleDoubleDouble(LLVMContext &C) { … }
static FunctionType *makeX86FP80X86FP80X86FP80X86FP80(LLVMContext &C) { … }
const KnownIntrinsic::WidenedIntrinsic KnownIntrinsic::kWidenedIntrinsics[] = …;
const KnownIntrinsic::LFEntry KnownIntrinsic::kLibfuncIntrinsics[] = …;
const char *KnownIntrinsic::get(LibFunc LFunc) { … }
const KnownIntrinsic::WidenedIntrinsic *KnownIntrinsic::widen(StringRef Name) { … }
static const char *getIntrinsicFromLibfunc(Function &Fn, Type *VT,
const TargetLibraryInfo &TLI) { … }
Value *NumericalStabilitySanitizer::maybeHandleKnownCallBase(
CallBase &Call, Type *VT, Type *ExtendedVT, const TargetLibraryInfo &TLI,
const ValueToShadowMap &Map, IRBuilder<> &Builder) { … }
Value *NumericalStabilitySanitizer::handleCallBase(CallBase &Call, Type *VT,
Type *ExtendedVT,
const TargetLibraryInfo &TLI,
const ValueToShadowMap &Map,
IRBuilder<> &Builder) { … }
Value *NumericalStabilitySanitizer::createShadowValueWithOperandsAvailable(
Instruction &Inst, const TargetLibraryInfo &TLI,
const ValueToShadowMap &Map) { … }
void NumericalStabilitySanitizer::maybeCreateShadowValue(
Instruction &Root, const TargetLibraryInfo &TLI, ValueToShadowMap &Map) { … }
void NumericalStabilitySanitizer::propagateFTStore(
StoreInst &Store, Type *VT, Type *ExtendedVT, const ValueToShadowMap &Map) { … }
void NumericalStabilitySanitizer::propagateNonFTStore(
StoreInst &Store, Type *VT, const ValueToShadowMap &Map) { … }
void NumericalStabilitySanitizer::propagateShadowValues(
Instruction &Inst, const TargetLibraryInfo &TLI,
const ValueToShadowMap &Map) { … }
static void moveFastMathFlags(Function &F,
std::vector<Instruction *> &Instructions) { … }
bool NumericalStabilitySanitizer::sanitizeFunction(
Function &F, const TargetLibraryInfo &TLI) { … }
static uint64_t GetMemOpSize(Value *V) { … }
bool NumericalStabilitySanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { … }
void NumericalStabilitySanitizer::maybeAddSuffixForNsanInterface(CallBase *CI) { … }