Skip to content

Commit 6824654

Browse files
committed
[ubsan] Connect -fsanitize-skip-hot-cutoff to LowerAllowCheckPass<cutoffs>
This adds the plumbing between -fsanitize-skip-hot-cutoff (introduced in llvm#121619) and LowerAllowCheckPass<cutoffs> (introduced in llvm#124211). 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 a080498 commit 6824654

File tree

5 files changed

+134
-72
lines changed

5 files changed

+134
-72
lines changed

clang/lib/CodeGen/BackendUtil.cpp

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

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

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3614,29 +3614,35 @@ void CodeGenFunction::EmitCheck(
36143614
llvm::Value *RecoverableCond = nullptr;
36153615
llvm::Value *TrapCond = nullptr;
36163616
bool NoMerge = false;
3617+
// Expand checks into:
3618+
// (Check1 || !allow_ubsan_check) && (Check2 || !allow_ubsan_check) ...
3619+
// We need separate allow_ubsan_check intrinsics because they have separately
3620+
// specified cutoffs.
3621+
// This expression looks expensive but will be simplified after
3622+
// LowerAllowCheckPass.
3623+
static const double SanitizerMaskCutoffsEps = 0.000000001f;
36173624
for (auto &[Check, Ord] : Checked) {
3625+
llvm::Value *GuardedCheck = Check;
3626+
if (ClSanitizeGuardChecks ||
3627+
(CGM.getCodeGenOpts().SanitizeSkipHotCutoffs[Ord] >
3628+
SanitizerMaskCutoffsEps)) {
3629+
llvm::Value *Allow = Builder.CreateCall(
3630+
CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check),
3631+
llvm::ConstantInt::get(CGM.Int8Ty, Ord));
3632+
GuardedCheck = Builder.CreateOr(Check, Builder.CreateNot(Allow));
3633+
}
3634+
36183635
// -fsanitize-trap= overrides -fsanitize-recover=.
36193636
llvm::Value *&Cond = CGM.getCodeGenOpts().SanitizeTrap.has(Ord) ? TrapCond
36203637
: CGM.getCodeGenOpts().SanitizeRecover.has(Ord)
36213638
? RecoverableCond
36223639
: FatalCond;
3623-
Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;
3640+
Cond = Cond ? Builder.CreateAnd(Cond, GuardedCheck) : GuardedCheck;
36243641

36253642
if (!CGM.getCodeGenOpts().SanitizeMergeHandlers.has(Ord))
36263643
NoMerge = true;
36273644
}
36283645

3629-
if (ClSanitizeGuardChecks) {
3630-
llvm::Value *Allow =
3631-
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check),
3632-
llvm::ConstantInt::get(CGM.Int8Ty, CheckHandler));
3633-
3634-
for (llvm::Value **Cond : {&FatalCond, &RecoverableCond, &TrapCond}) {
3635-
if (*Cond)
3636-
*Cond = Builder.CreateOr(*Cond, Builder.CreateNot(Allow));
3637-
}
3638-
}
3639-
36403646
if (TrapCond)
36413647
EmitTrapCheck(TrapCond, CheckHandler, NoMerge);
36423648
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)