Skip to content

Commit 5d1944f

Browse files
committed
[ubsan] Plumb through -fsanitize-skip-hot-cutoff to LowerAllowCheckPass
This passes through the values of -fsanitize-skip-hot-cutoff (introduced patch in llvm#121619) to the LowerAllowCheckPass, via the Options parameter (introduced in llvm#122994), and adjusts the instrumentation accordingly. The net effect is that -fsanitize-skip-hot-cutoff now combines the functionality of -ubsan-guard-checks and -lower-allow-check-percentile-cutoff (though this patch does not remove those yet), and generalizes the latter to allow per-sanitizer cutoffs. Note: this patch replaces Intrinsic::allow_ubsan_check's SanitizerHandler parameter with SanitizerOrdinal; this is necessary because the hot cutoffs are specified in terms of SanitizerOrdinal (e.g., null, alignment), not SanitizerHandler (e.g., TypeMismatch).
1 parent ec15b24 commit 5d1944f

File tree

10 files changed

+221
-94
lines changed

10 files changed

+221
-94
lines changed

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,12 +794,37 @@ static void addSanitizers(const Triple &TargetTriple,
794794
PB.registerOptimizerLastEPCallback(SanitizersCallback);
795795
}
796796

797-
if (LowerAllowCheckPass::IsRequested()) {
797+
bool lowerAllowCheck = LowerAllowCheckPass::IsRequested();
798+
// Is there a non-zero cutoff?
799+
static const double SanitizerMaskCutoffsEps = 0.000000001f;
800+
for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) {
801+
std::optional<double> maybeCutoff = CodeGenOpts.SanitizeSkipHotCutoffs[i];
802+
lowerAllowCheck |= (maybeCutoff.has_value() &&
803+
(maybeCutoff.value() > SanitizerMaskCutoffsEps));
804+
}
805+
806+
if (lowerAllowCheck) {
798807
// We want to call it after inline, which is about OptimizerEarlyEPCallback.
799808
PB.registerOptimizerEarlyEPCallback([&](ModulePassManager &MPM,
800809
OptimizationLevel Level,
801810
ThinOrFullLTOPhase Phase) {
802811
LowerAllowCheckPass::Options Opts;
812+
813+
// SanitizeSkipHotCutoffs stores doubles with range [0, 1]
814+
// Opts.cutoffs wants ints with range [0, 999999]
815+
for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) {
816+
std::optional<double> maybeCutoff =
817+
CodeGenOpts.SanitizeSkipHotCutoffs[i];
818+
if (maybeCutoff.has_value() &&
819+
(maybeCutoff.value() > SanitizerMaskCutoffsEps)) {
820+
Opts.cutoffs.push_back(
821+
std::clamp((int)(maybeCutoff.value() * 1000000), 0, 999999));
822+
} else {
823+
// Default is don't skip the check
824+
Opts.cutoffs.push_back(0);
825+
}
826+
}
827+
803828
MPM.addPass(createModuleToFunctionPassAdaptor(LowerAllowCheckPass(Opts)));
804829
});
805830
}

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3607,29 +3607,35 @@ void CodeGenFunction::EmitCheck(
36073607
llvm::Value *RecoverableCond = nullptr;
36083608
llvm::Value *TrapCond = nullptr;
36093609
bool NoMerge = false;
3610+
// Expand checks into:
3611+
// (Check1 || !allow_ubsan_check) && (Check2 || !allow_ubsan_check) ...
3612+
// We need separate allow_ubsan_check intrinsics because they have separately
3613+
// specified cutoffs.
3614+
// This expression looks expensive but will be simplified after
3615+
// LowerAllowCheckPass.
3616+
static const double SanitizerMaskCutoffsEps = 0.000000001f;
36103617
for (auto &[Check, Ord] : Checked) {
3618+
llvm::Value *GuardedCheck = Check;
3619+
if (ClSanitizeGuardChecks ||
3620+
(CGM.getCodeGenOpts().SanitizeSkipHotCutoffs[Ord] >
3621+
SanitizerMaskCutoffsEps)) {
3622+
llvm::Value *Allow = Builder.CreateCall(
3623+
CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check),
3624+
llvm::ConstantInt::get(CGM.Int8Ty, Ord));
3625+
GuardedCheck = Builder.CreateOr(Check, Builder.CreateNot(Allow));
3626+
}
3627+
36113628
// -fsanitize-trap= overrides -fsanitize-recover=.
36123629
llvm::Value *&Cond = CGM.getCodeGenOpts().SanitizeTrap.has(Ord) ? TrapCond
36133630
: CGM.getCodeGenOpts().SanitizeRecover.has(Ord)
36143631
? RecoverableCond
36153632
: FatalCond;
3616-
Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;
3633+
Cond = Cond ? Builder.CreateAnd(Cond, GuardedCheck) : GuardedCheck;
36173634

36183635
if (!CGM.getCodeGenOpts().SanitizeMergeHandlers.has(Ord))
36193636
NoMerge = true;
36203637
}
36213638

3622-
if (ClSanitizeGuardChecks) {
3623-
llvm::Value *Allow =
3624-
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check),
3625-
llvm::ConstantInt::get(CGM.Int8Ty, CheckHandler));
3626-
3627-
for (llvm::Value **Cond : {&FatalCond, &RecoverableCond, &TrapCond}) {
3628-
if (*Cond)
3629-
*Cond = Builder.CreateOr(*Cond, Builder.CreateNot(Allow));
3630-
}
3631-
}
3632-
36333639
if (TrapCond)
36343640
EmitTrapCheck(TrapCond, CheckHandler, NoMerge);
36353641
if (!FatalCond && !RecoverableCond)

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2314,7 +2314,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
23142314
Opts.SanitizeSkipHotCutoffs = parseSanitizerWeightedKinds(
23152315
"-fsanitize-skip-hot-cutoff=",
23162316
Args.getAllArgValues(OPT_fsanitize_skip_hot_cutoff_EQ), Diags);
2317-
23182317
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
23192318

23202319
if (!LangOpts->CUDAIsDevice)

clang/test/CodeGen/allow-ubsan-check-inline.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// 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:"
2+
// 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:"
3+
//
4+
// -ubsan-guard-checks is deprecated and will be removed in the future;
5+
// use -fsanitize-skip-hot-cutoff, as shown above.
16
// 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:"
27
// 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:"
38

0 commit comments

Comments
 (0)