Skip to content
27 changes: 26 additions & 1 deletion clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,12 +794,37 @@ static void addSanitizers(const Triple &TargetTriple,
PB.registerOptimizerLastEPCallback(SanitizersCallback);
}

if (LowerAllowCheckPass::IsRequested()) {
bool lowerAllowCheck = LowerAllowCheckPass::IsRequested();
// Is there a non-zero cutoff?
static const double SanitizerMaskCutoffsEps = 0.000000001f;
for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) {
std::optional<double> maybeCutoff = CodeGenOpts.SanitizeSkipHotCutoffs[i];
lowerAllowCheck |= (maybeCutoff.has_value() &&
(maybeCutoff.value() > SanitizerMaskCutoffsEps));
}

if (lowerAllowCheck) {
// We want to call it after inline, which is about OptimizerEarlyEPCallback.
PB.registerOptimizerEarlyEPCallback([&](ModulePassManager &MPM,
OptimizationLevel Level,
ThinOrFullLTOPhase Phase) {
LowerAllowCheckPass::Options Opts;

// SanitizeSkipHotCutoffs stores doubles with range [0, 1]
// Opts.cutoffs wants ints with range [0, 999999]
for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) {
std::optional<double> maybeCutoff =
CodeGenOpts.SanitizeSkipHotCutoffs[i];
if (maybeCutoff.has_value() &&
(maybeCutoff.value() > SanitizerMaskCutoffsEps)) {
Opts.cutoffs.push_back(
std::clamp((int)(maybeCutoff.value() * 1000000), 0, 999999));
} else {
// Default is don't skip the check
Opts.cutoffs.push_back(0);
}
}

MPM.addPass(createModuleToFunctionPassAdaptor(LowerAllowCheckPass(Opts)));
});
}
Expand Down
30 changes: 18 additions & 12 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3607,29 +3607,35 @@ void CodeGenFunction::EmitCheck(
llvm::Value *RecoverableCond = nullptr;
llvm::Value *TrapCond = nullptr;
bool NoMerge = false;
// Expand checks into:
// (Check1 || !allow_ubsan_check) && (Check2 || !allow_ubsan_check) ...
// We need separate allow_ubsan_check intrinsics because they have separately
// specified cutoffs.
// This expression looks expensive but will be simplified after
// LowerAllowCheckPass.
static const double SanitizerMaskCutoffsEps = 0.000000001f;
for (auto &[Check, Ord] : Checked) {
llvm::Value *GuardedCheck = Check;
if (ClSanitizeGuardChecks ||
(CGM.getCodeGenOpts().SanitizeSkipHotCutoffs[Ord] >
SanitizerMaskCutoffsEps)) {
llvm::Value *Allow = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check),
llvm::ConstantInt::get(CGM.Int8Ty, Ord));
GuardedCheck = Builder.CreateOr(Check, Builder.CreateNot(Allow));
}

// -fsanitize-trap= overrides -fsanitize-recover=.
llvm::Value *&Cond = CGM.getCodeGenOpts().SanitizeTrap.has(Ord) ? TrapCond
: CGM.getCodeGenOpts().SanitizeRecover.has(Ord)
? RecoverableCond
: FatalCond;
Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;
Cond = Cond ? Builder.CreateAnd(Cond, GuardedCheck) : GuardedCheck;

if (!CGM.getCodeGenOpts().SanitizeMergeHandlers.has(Ord))
NoMerge = true;
}

if (ClSanitizeGuardChecks) {
llvm::Value *Allow =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check),
llvm::ConstantInt::get(CGM.Int8Ty, CheckHandler));

for (llvm::Value **Cond : {&FatalCond, &RecoverableCond, &TrapCond}) {
if (*Cond)
*Cond = Builder.CreateOr(*Cond, Builder.CreateNot(Allow));
}
}

if (TrapCond)
EmitTrapCheck(TrapCond, CheckHandler, NoMerge);
if (!FatalCond && !RecoverableCond)
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2314,7 +2314,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.SanitizeSkipHotCutoffs = parseSanitizerWeightedKinds(
"-fsanitize-skip-hot-cutoff=",
Args.getAllArgValues(OPT_fsanitize_skip_hot_cutoff_EQ), Diags);

Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);

if (!LangOpts->CUDAIsDevice)
Expand Down
5 changes: 5 additions & 0 deletions clang/test/CodeGen/allow-ubsan-check-inline.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -fsanitize-skip-hot-cutoff=signed-integer-overflow=0.000001 -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check -fno-inline 2>&1 | FileCheck %s --check-prefixes=NOINL --implicit-check-not="remark:"
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -fsanitize-skip-hot-cutoff=signed-integer-overflow=0.000001 -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check 2>&1 | FileCheck %s --check-prefixes=INLINE --implicit-check-not="remark:"
//
// -ubsan-guard-checks is deprecated and will be removed in the future;
// use -fsanitize-skip-hot-cutoff, as shown above.
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -mllvm -ubsan-guard-checks -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check -fno-inline 2>&1 | FileCheck %s --check-prefixes=NOINL --implicit-check-not="remark:"
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -mllvm -ubsan-guard-checks -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check 2>&1 | FileCheck %s --check-prefixes=INLINE --implicit-check-not="remark:"

Expand Down
Loading
Loading