Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// Set of sanitizer checks that trap rather than diagnose.
SanitizerSet SanitizeTrap;

/// Set of sanitizer checks that have non-merged handlers (better
/// debuggability at the expense of code size).
SanitizerSet SanitizeNonMergedHandlers;

/// List of backend command-line options for -fembed-bitcode.
std::vector<uint8_t> CmdArgs;

Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2548,6 +2548,14 @@ def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Gro
def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
Visibility<[ClangOption, CLOption]>,
HelpText<"Disable trapping for specified sanitizers">;
def fsanitize_nonmerged_handlers_EQ
: CommaJoined<["-"], "fsanitize-nonmerged-handlers=">,
Group<f_clang_Group>,
HelpText<"Enable non-merged handlers for specified sanitizers">;
def fno_sanitize_nonmerged_handlers_EQ
: CommaJoined<["-"], "fno-sanitize-nonmerged-handlers=">,
Group<f_clang_Group>,
HelpText<"Disable non-merged handlers for specified sanitizers">;
def fsanitize_trap : Flag<["-"], "fsanitize-trap">, Group<f_clang_Group>,
Alias<fsanitize_trap_EQ>, AliasArgs<["all"]>,
HelpText<"Enable trapping for all sanitizers">;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class SanitizerArgs {
SanitizerSet Sanitizers;
SanitizerSet RecoverableSanitizers;
SanitizerSet TrapSanitizers;
SanitizerSet NonMergedHandlers;

std::vector<std::string> UserIgnorelistFiles;
std::vector<std::string> SystemIgnorelistFiles;
Expand Down
30 changes: 17 additions & 13 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3546,7 +3546,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
ArrayRef<llvm::Value *> FnArgs,
SanitizerHandler CheckHandler,
CheckRecoverableKind RecoverKind, bool IsFatal,
llvm::BasicBlock *ContBB) {
llvm::BasicBlock *ContBB, bool NoMerge) {
assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable);
std::optional<ApplyDebugLocation> DL;
if (!CGF.Builder.getCurrentDebugLocation()) {
Expand Down Expand Up @@ -3581,10 +3581,9 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
llvm::AttributeList::FunctionIndex, B),
/*Local=*/true);
llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs);
bool NoMerge =
ClSanitizeDebugDeoptimization ||
!CGF.CGM.getCodeGenOpts().OptimizationLevel ||
(CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
NoMerge = NoMerge || ClSanitizeDebugDeoptimization ||
!CGF.CGM.getCodeGenOpts().OptimizationLevel ||
(CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
if (NoMerge)
HandlerCall->addFnAttr(llvm::Attribute::NoMerge);
if (!MayReturn) {
Expand All @@ -3608,6 +3607,7 @@ void CodeGenFunction::EmitCheck(
llvm::Value *FatalCond = nullptr;
llvm::Value *RecoverableCond = nullptr;
llvm::Value *TrapCond = nullptr;
bool NoMerge = false;
for (int i = 0, n = Checked.size(); i < n; ++i) {
llvm::Value *Check = Checked[i].first;
// -fsanitize-trap= overrides -fsanitize-recover=.
Expand All @@ -3618,6 +3618,9 @@ void CodeGenFunction::EmitCheck(
? RecoverableCond
: FatalCond;
Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check;

if (CGM.getCodeGenOpts().SanitizeNonMergedHandlers.has(Checked[i].second))
NoMerge = true;
}

if (ClSanitizeGuardChecks) {
Expand All @@ -3632,7 +3635,7 @@ void CodeGenFunction::EmitCheck(
}

if (TrapCond)
EmitTrapCheck(TrapCond, CheckHandler);
EmitTrapCheck(TrapCond, CheckHandler, NoMerge);
if (!FatalCond && !RecoverableCond)
return;

Expand Down Expand Up @@ -3698,7 +3701,7 @@ void CodeGenFunction::EmitCheck(
// Simple case: we need to generate a single handler call, either
// fatal, or non-fatal.
emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind,
(FatalCond != nullptr), Cont);
(FatalCond != nullptr), Cont, NoMerge);
} else {
// Emit two handler calls: first one for set of unrecoverable checks,
// another one for recoverable.
Expand All @@ -3708,10 +3711,10 @@ void CodeGenFunction::EmitCheck(
Builder.CreateCondBr(FatalCond, NonFatalHandlerBB, FatalHandlerBB);
EmitBlock(FatalHandlerBB);
emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, true,
NonFatalHandlerBB);
NonFatalHandlerBB, NoMerge);
EmitBlock(NonFatalHandlerBB);
emitCheckHandlerCall(*this, FnType, Args, CheckHandler, RecoverKind, false,
Cont);
Cont, NoMerge);
}

EmitBlock(Cont);
Expand Down Expand Up @@ -3901,7 +3904,8 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {
}

void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
SanitizerHandler CheckHandlerID) {
SanitizerHandler CheckHandlerID,
bool NoMerge) {
llvm::BasicBlock *Cont = createBasicBlock("cont");

// If we're optimizing, collapse all calls to trap down to just one per
Expand All @@ -3911,9 +3915,9 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,

llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];

bool NoMerge = ClSanitizeDebugDeoptimization ||
!CGM.getCodeGenOpts().OptimizationLevel ||
(CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
NoMerge = NoMerge || ClSanitizeDebugDeoptimization ||
!CGM.getCodeGenOpts().OptimizationLevel ||
(CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());

if (TrapBB && !NoMerge) {
auto Call = TrapBB->begin();
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5166,7 +5166,8 @@ class CodeGenFunction : public CodeGenTypeCache {

/// Create a basic block that will call the trap intrinsic, and emit a
/// conditional branch to it, for the -ftrapv checks.
void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID);
void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID,
bool NoMerge = false);

/// Emit a call to trap or debugtrap and attach function attribute
/// "trap-func-name" if specified.
Expand Down
37 changes: 30 additions & 7 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ static const SanitizerMask TrappingSupported =
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::LocalBounds | SanitizerKind::CFI |
SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
static const SanitizerMask NonMergedDefault;
static const SanitizerMask NonMergedSupported = SanitizerKind::Undefined;
static const SanitizerMask TrappingDefault = SanitizerKind::CFI;
static const SanitizerMask CFIClasses =
SanitizerKind::CFIVCall | SanitizerKind::CFINVCall |
Expand Down Expand Up @@ -696,6 +698,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
TrappingKinds &= Kinds;
RecoverableKinds &= ~TrappingKinds;

// Parse -f(no-)?sanitize-nonmerged-handlers flags
SanitizerMask AlwaysNonMerged; // Empty
SanitizerMask NeverNonMerged = ~(setGroupBits(NonMergedSupported));
SanitizerMask NonMergedKinds = parseSanitizeArgs(
D, Args, DiagnoseErrors, NonMergedDefault, AlwaysNonMerged,
NeverNonMerged, options::OPT_fsanitize_nonmerged_handlers_EQ,
options::OPT_fno_sanitize_nonmerged_handlers_EQ);
NonMergedKinds |= AlwaysNonMerged;
NonMergedKinds &= ~NeverNonMerged;
NonMergedKinds &= Kinds;

// Setup ignorelist files.
// Add default ignorelist from resource directory for activated sanitizers,
// and validate special case lists format.
Expand Down Expand Up @@ -1113,6 +1126,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
TrapSanitizers.Mask |= TrappingKinds;
assert(!(RecoverableKinds & TrappingKinds) &&
"Overlap between recoverable and trapping sanitizers");

NonMergedHandlers.Mask |= NonMergedKinds;
}

static std::string toString(const clang::SanitizerSet &Sanitizers) {
Expand Down Expand Up @@ -1274,6 +1289,10 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));

if (!NonMergedHandlers.empty())
CmdArgs.push_back(Args.MakeArgString("-fsanitize-nonmerged-handlers=" +
toString(NonMergedHandlers)));

addSpecialCaseListOpt(Args, CmdArgs,
"-fsanitize-ignorelist=", UserIgnorelistFiles);
addSpecialCaseListOpt(Args, CmdArgs,
Expand Down Expand Up @@ -1441,13 +1460,17 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,

SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors) {
assert((A->getOption().matches(options::OPT_fsanitize_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) &&
"Invalid argument in parseArgValues!");
assert(
(A->getOption().matches(options::OPT_fsanitize_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_EQ) ||
A->getOption().matches(options::OPT_fsanitize_recover_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_recover_EQ) ||
A->getOption().matches(options::OPT_fsanitize_trap_EQ) ||
A->getOption().matches(options::OPT_fno_sanitize_trap_EQ) ||
A->getOption().matches(options::OPT_fsanitize_nonmerged_handlers_EQ) ||
A->getOption().matches(
options::OPT_fno_sanitize_nonmerged_handlers_EQ)) &&
"Invalid argument in parseArgValues!");
SanitizerMask Kinds;
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
const char *Value = A->getValue(i);
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,10 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeTrap))
GenerateArg(Consumer, OPT_fsanitize_trap_EQ, Sanitizer);

for (StringRef Sanitizer :
serializeSanitizerKinds(Opts.SanitizeNonMergedHandlers))
GenerateArg(Consumer, OPT_fsanitize_nonmerged_handlers_EQ, Sanitizer);

if (!Opts.EmitVersionIdentMetadata)
GenerateArg(Consumer, OPT_Qn);

Expand Down Expand Up @@ -2269,6 +2273,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
parseSanitizerKinds("-fsanitize-trap=",
Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags,
Opts.SanitizeTrap);
parseSanitizerKinds("-fsanitize-nonmerged-handlers=",
Args.getAllArgValues(OPT_fsanitize_nonmerged_handlers_EQ),
Diags, Opts.SanitizeNonMergedHandlers);

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

Expand Down
7 changes: 6 additions & 1 deletion clang/test/CodeGen/ubsan-trap-merge.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
// NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// The most important assertion is the attributes at the end of the file, which
// shows whether -ubsan-unique-traps attaches 'nomerge' to each ubsan call.
// shows whether -ubsan-unique-traps and -fsanitize-nonmerged-handlers attach
// 'nomerge' to each ubsan call.
//
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - | FileCheck %s --check-prefix=HANDLER
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - -fsanitize-minimal-runtime | FileCheck %s --check-prefix=MINRT
//
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow %s -o - -fsanitize-trap=signed-integer-overflow | FileCheck %s --check-prefix=TRAP
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow %s -o - | FileCheck %s --check-prefix=HANDLER
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -O3 -fsanitize-nonmerged-handlers=signed-integer-overflow %s -o - -fsanitize-minimal-runtime | FileCheck %s --check-prefix=MINRT
//
// REQUIRES: x86-registered-target

// TRAP-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f(
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Driver/fsanitize.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"

// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-nonmerged-handlers=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NONMERGED
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -fsanitize-nonmerged-handlers=undefined -fno-sanitize-nonmerged-handlers=signed-integer-overflow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NONMERGED2
// CHECK-UNDEFINED-NONMERGED: "-fsanitize-nonmerged-handlers=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
// CHECK-UNDEFINED-NONMERGED2: "-fsanitize-nonmerged-handlers=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"

// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}}

Expand Down
Loading