Skip to content

Commit 0443630

Browse files
committed
merge main into amd-staging
2 parents 12e582c + 435dbba commit 0443630

File tree

79 files changed

+1449
-414
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+1449
-414
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0, Benign) ///< Enable use-after-delet
270270
CODEGENOPT(SanitizeCfiCrossDso, 1, 0, Benign) ///< Enable cross-dso support in CFI.
271271
CODEGENOPT(SanitizeMinimalRuntime, 1, 0, Benign) ///< Use "_minimal" sanitizer runtime for
272272
///< diagnostics.
273+
CODEGENOPT(SanitizeHandlerPreserveAllRegs, 1, 0, Benign) ///< Use "_preserve" sanitizer runtime for
274+
///< diagnostics.
273275
CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0, Benign) ///< Generalize pointer types in
274276
///< CFI icall function signatures
275277
CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0, Benign) ///< Normalize integer types in

clang/include/clang/Driver/SanitizerArgs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class SanitizerArgs {
6868
bool TsanAtomics = true;
6969
bool MinimalRuntime = false;
7070
bool TysanOutlineInstrumentation = true;
71+
bool HandlerPreserveAllRegs = false;
7172
// True if cross-dso CFI support if provided by the system (i.e. Android).
7273
bool ImplicitCfiRuntime = false;
7374
bool NeedsMemProfRt = false;

clang/include/clang/Options/Options.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2672,6 +2672,15 @@ defm sanitize_minimal_runtime : BoolOption<"f", "sanitize-minimal-runtime",
26722672
PosFlag<SetTrue>,
26732673
NegFlag<SetFalse>>,
26742674
Group<f_clang_Group>;
2675+
defm sanitize_handler_preserve_all_regs
2676+
: BoolOption<
2677+
"f", "sanitize-handler-preserve-all-regs",
2678+
CodeGenOpts<"SanitizeHandlerPreserveAllRegs">, DefaultFalse,
2679+
PosFlag<SetTrue, [], [],
2680+
"Enable handlers with preserve_all calling convention">,
2681+
NegFlag<SetFalse, [], [],
2682+
"Disable handlers with preserve_all calling convention">>,
2683+
Group<f_clang_Group>;
26752684
def fsanitize_link_runtime : Flag<["-"], "fsanitize-link-runtime">,
26762685
Group<f_clang_Group>;
26772686
def fno_sanitize_link_runtime : Flag<["-"], "fno-sanitize-link-runtime">,

clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ cir::FuncOp LoweringPreparePass::getOrCreateDtorFunc(CIRBaseBuilderTy &builder,
702702
cir::GlobalOp op,
703703
mlir::Region &dtorRegion,
704704
cir::CallOp &dtorCall) {
705+
mlir::OpBuilder::InsertionGuard guard(builder);
705706
assert(!cir::MissingFeatures::astVarDeclInterface());
706707
assert(!cir::MissingFeatures::opGlobalThreadLocal());
707708

clang/lib/Driver/SanitizerArgs.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
423423
MinimalRuntime =
424424
Args.hasFlag(options::OPT_fsanitize_minimal_runtime,
425425
options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime);
426+
HandlerPreserveAllRegs =
427+
Args.hasFlag(options::OPT_fsanitize_handler_preserve_all_regs,
428+
options::OPT_fno_sanitize_handler_preserve_all_regs,
429+
HandlerPreserveAllRegs);
426430

427431
// The object size sanitizer should not be enabled at -O0.
428432
Arg *OptLevel = Args.getLastArg(options::OPT_O_Group);
@@ -1476,6 +1480,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
14761480
if (MinimalRuntime)
14771481
CmdArgs.push_back("-fsanitize-minimal-runtime");
14781482

1483+
if (HandlerPreserveAllRegs)
1484+
CmdArgs.push_back("-fsanitize-handler-preserve-all-regs");
1485+
14791486
if (AsanFieldPadding)
14801487
CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
14811488
Twine(AsanFieldPadding)));

clang/lib/Tooling/Transformer/RangeSelector.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ RangeSelector transformer::node(std::string ID) {
139139
(Node->get<Stmt>() != nullptr && Node->get<Expr>() == nullptr))
140140
? tooling::getExtendedRange(*Node, tok::TokenKind::semi,
141141
*Result.Context)
142-
: CharSourceRange::getTokenRange(Node->getSourceRange());
142+
: CharSourceRange::getTokenRange(
143+
Node->getSourceRange(/*IncludeQualifier=*/true));
143144
};
144145
}
145146

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir
2+
// RUN: FileCheck --input-file=%t-before.cir %s --check-prefix=CIR-BEFORE-LPP
3+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
4+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
5+
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
6+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
7+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
8+
9+
// This duplicates a test case in global-init.cpp, but having it by itself
10+
// forces the __cxa_atexit function to be emitted for this case, which was
11+
// broken in the original implementation.
12+
13+
struct ArrayDtor {
14+
~ArrayDtor();
15+
};
16+
17+
ArrayDtor arrDtor[16];
18+
19+
// CIR-BEFORE-LPP: cir.global external @arrDtor = #cir.zero : !cir.array<!rec_ArrayDtor x 16>
20+
// CIR-BEFORE-LPP-SAME: dtor {
21+
// CIR-BEFORE-LPP: %[[THIS:.*]] = cir.get_global @arrDtor : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>>
22+
// CIR-BEFORE-LPP: cir.array.dtor %[[THIS]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> {
23+
// CIR-BEFORE-LPP: ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_ArrayDtor>):
24+
// CIR-BEFORE-LPP: cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr<!rec_ArrayDtor>) -> ()
25+
// CIR-BEFORE-LPP: cir.yield
26+
// CIR-BEFORE-LPP: }
27+
// CIR-BEFORE-LPP: }
28+
29+
// CIR: cir.global external @arrDtor = #cir.zero : !cir.array<!rec_ArrayDtor x 16> {alignment = 16 : i64}
30+
// CIR: cir.func internal private @__cxx_global_array_dtor(%[[ARR_ARG:.*]]: !cir.ptr<!void> {{.*}}) {
31+
// CIR: %[[CONST15:.*]] = cir.const #cir.int<15> : !u64i
32+
// CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARR_ARG]] : !cir.ptr<!void> -> !cir.ptr<!rec_ArrayDtor>
33+
// CIR: %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[CONST15]] : (!cir.ptr<!rec_ArrayDtor>, !u64i) -> !cir.ptr<!rec_ArrayDtor>
34+
// CIR: %[[CUR_ADDR:.*]] = cir.alloca !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, ["__array_idx"]
35+
// CIR: cir.store %[[END]], %[[CUR_ADDR]] : !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>>
36+
// CIR: cir.do {
37+
// CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, !cir.ptr<!rec_ArrayDtor>
38+
// CIR: cir.call @_ZN9ArrayDtorD1Ev(%[[CUR]]) nothrow : (!cir.ptr<!rec_ArrayDtor>) -> ()
39+
// CIR: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i
40+
// CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[NEG_ONE]] : (!cir.ptr<!rec_ArrayDtor>, !s64i) -> !cir.ptr<!rec_ArrayDtor>
41+
// CIR: cir.store %[[NEXT]], %[[CUR_ADDR]] : !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>>
42+
// CIR: cir.yield
43+
// CIR: } while {
44+
// CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, !cir.ptr<!rec_ArrayDtor>
45+
// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[BEGIN]]) : !cir.ptr<!rec_ArrayDtor>, !cir.bool
46+
// CIR: cir.condition(%[[CMP]])
47+
// CIR: }
48+
// CIR: cir.return
49+
// CIR: }
50+
//
51+
// CIR: cir.func internal private @__cxx_global_var_init() {
52+
// CIR: %[[ARR:.*]] = cir.get_global @arrDtor : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>>
53+
// CIR: %[[DTOR:.*]] = cir.get_global @__cxx_global_array_dtor : !cir.ptr<!cir.func<(!cir.ptr<!void>)>>
54+
// CIR: %[[DTOR_CAST:.*]] = cir.cast bitcast %[[DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!void>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>>
55+
// CIR: %[[ARR_CAST:.*]] = cir.cast bitcast %[[ARR]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> -> !cir.ptr<!void>
56+
// CIR: %[[HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8>
57+
// CIR: cir.call @__cxa_atexit(%[[DTOR_CAST]], %[[ARR_CAST]], %[[HANDLE]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>)>>, !cir.ptr<!void>, !cir.ptr<i8>) -> ()
58+
59+
// LLVM: define internal void @__cxx_global_array_dtor(ptr %[[ARR_ARG:.*]]) {
60+
// LLVM: %[[BEGIN:.*]] = getelementptr %struct.ArrayDtor, ptr %[[ARR_ARG]], i32 0
61+
// LLVM: %[[END:.*]] = getelementptr %struct.ArrayDtor, ptr %[[BEGIN]], i64 15
62+
// LLVM: %[[CUR_ADDR:.*]] = alloca ptr
63+
// LLVM: store ptr %[[END]], ptr %[[CUR_ADDR]]
64+
// LLVM: br label %[[LOOP_BODY:.*]]
65+
// LLVM: [[LOOP_COND:.*]]:
66+
// LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]]
67+
// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[BEGIN]]
68+
// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]]
69+
// LLVM: [[LOOP_BODY]]:
70+
// LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]]
71+
// LLVM: call void @_ZN9ArrayDtorD1Ev(ptr %[[CUR]]) #0
72+
// LLVM: %[[PREV:.*]] = getelementptr %struct.ArrayDtor, ptr %[[CUR]], i64 -1
73+
// LLVM: store ptr %[[PREV]], ptr %[[CUR_ADDR]]
74+
// LLVM: br label %[[LOOP_COND]]
75+
// LLVM: [[LOOP_END]]:
76+
// LLVM: ret void
77+
// LLVM: }
78+
//
79+
// LLVM: define internal void @__cxx_global_var_init() {
80+
// LLVM: call void @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr @arrDtor, ptr @__dso_handle)
81+
82+
// Note: OGCG defines these functions in reverse order of CIR->LLVM.
83+
// Note also: OGCG doesn't pass the address of the array to the destructor function.
84+
// Instead, it uses the global directly in the helper function.
85+
86+
// OGCG: define internal void @__cxx_global_var_init() {{.*}} section ".text.startup" {
87+
// OGCG: call i32 @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr null, ptr @__dso_handle)
88+
89+
// OGCG: define internal void @__cxx_global_array_dtor(ptr noundef %[[ARG:.*]]) {{.*}} section ".text.startup" {
90+
// OGCG: entry:
91+
// OGCG: %[[UNUSED_ADDR:.*]] = alloca ptr
92+
// OGCG: store ptr %[[ARG]], ptr %[[UNUSED_ADDR]]
93+
// OGCG: br label %[[LOOP_BODY:.*]]
94+
// OGCG: [[LOOP_BODY]]:
95+
// OGCG: %[[PREV:.*]] = phi ptr [ getelementptr inbounds (%struct.ArrayDtor, ptr @arrDtor, i64 16), %entry ], [ %[[CUR:.*]], %[[LOOP_BODY]] ]
96+
// OGCG: %[[CUR]] = getelementptr inbounds %struct.ArrayDtor, ptr %[[PREV]], i64 -1
97+
// OGCG: call void @_ZN9ArrayDtorD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %[[CUR]])
98+
// OGCG: %[[DONE:.*]] = icmp eq ptr %[[CUR]], @arrDtor
99+
// OGCG: br i1 %[[DONE]], label %[[LOOP_END:.*]], label %[[LOOP_BODY]]
100+
// OGCG: [[LOOP_END]]:
101+
// OGCG: ret void
102+
// OGCG: }
103+
104+
// Common init function for all globals with default priority
105+
106+
// CIR: cir.func private @_GLOBAL__sub_I_[[FILENAME:.*]]() {
107+
// CIR: cir.call @__cxx_global_var_init() : () -> ()
108+
109+
// LLVM: define void @_GLOBAL__sub_I_[[FILENAME:.*]]()
110+
// LLVM: call void @__cxx_global_var_init()
111+
112+
// OGCG: define internal void @_GLOBAL__sub_I_[[FILENAME:.*]]() {{.*}} section ".text.startup" {
113+
// OGCG: call void @__cxx_global_var_init()

clang/test/Driver/fsanitize.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,11 @@
984984
// CHECK-UBSAN-MINIMAL: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
985985
// CHECK-UBSAN-MINIMAL: "-fsanitize-minimal-runtime"
986986

987+
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-minimal-runtime -fsanitize-handler-preserve-all-regs %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-MINIMAL-PRESERVE
988+
// CHECK-UBSAN-MINIMAL-PRESERVE: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
989+
// CHECK-UBSAN-MINIMAL-PRESERVE: "-fsanitize-minimal-runtime"
990+
// CHECK-UBSAN-MINIMAL-PRESERVE: "-fsanitize-handler-preserve-all-regs
991+
987992
// RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fsanitize-trap=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTSAN-TRAP
988993
// CHECK-INTSAN-TRAP: "-fsanitize-trap=integer-divide-by-zero,shift-base,shift-exponent,signed-integer-overflow,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change"
989994

clang/unittests/Tooling/RangeSelectorTest.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,13 @@ TEST(RangeSelectorTest, NodeOpExpression) {
339339
EXPECT_THAT_EXPECTED(select(node("id"), Match), HasValue("3"));
340340
}
341341

342+
TEST(RangeSelectorTest, NodeOpTypeLoc) {
343+
StringRef Code = "namespace ns {struct Foo{};} ns::Foo a;";
344+
TestMatch Match =
345+
matchCode(Code, varDecl(hasTypeLoc(typeLoc().bind("typeloc"))));
346+
EXPECT_THAT_EXPECTED(select(node("typeloc"), Match), HasValue("ns::Foo"));
347+
}
348+
342349
TEST(RangeSelectorTest, StatementOp) {
343350
StringRef Code = "int f() { return 3; }";
344351
TestMatch Match = matchCode(Code, expr().bind("id"));

compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@ static void message(const char *msg) { ubsan_message(msg); }
1212
static void message(const char *msg) { (void)write(2, msg, strlen(msg)); }
1313
#endif
1414

15+
// If for some reason we cannot build the runtime with preserve_all, don't
16+
// emit any symbol. Programs that need them will fail to link, but that is
17+
// better than randomly corrupted registers.
18+
// Some architectures don't support preserve_all (but clang still has the)
19+
// attribute. For now, only support x86-64 and aarch64.
20+
#if defined(__clang__) && defined(__has_cpp_attribute) && \
21+
(defined(__x86_64__) || defined(__aarch64__))
22+
#if __has_cpp_attribute(clang::preserve_all)
23+
#define PRESERVE_HANDLERS true
24+
#else
25+
#define PRESERVE_HANDLERS false
26+
#endif
27+
#else
28+
#define PRESERVE_HANDLERS false
29+
#endif
30+
1531
static const int kMaxCallerPcs = 20;
1632
static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
1733
// Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means
@@ -85,6 +101,18 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
85101
}
86102
}
87103

104+
#if PRESERVE_HANDLERS
105+
SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_preserve,
106+
const char *kind, uintptr_t caller)
107+
[[clang::preserve_all]] {
108+
// Additional indirecton so the user can override this with their own
109+
// preserve_all function. This would allow, e.g., a function that reports the
110+
// first error only, so for all subsequent calls we can skip the register save
111+
// / restore.
112+
__ubsan_report_error(kind, caller);
113+
}
114+
#endif
115+
88116
SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_fatal, const char *kind,
89117
uintptr_t caller) {
90118
// Use another handlers, in case it's already overriden.
@@ -119,6 +147,16 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
119147

120148
#define INTERFACE extern "C" __attribute__((visibility("default")))
121149

150+
#if PRESERVE_HANDLERS
151+
#define HANDLER_PRESERVE(name, kind) \
152+
INTERFACE void __ubsan_handle_##name##_minimal_preserve() \
153+
[[clang::preserve_all]] { \
154+
__ubsan_report_error_preserve(kind, GET_CALLER_PC()); \
155+
}
156+
#else
157+
#define HANDLER_PRESERVE(name, kind)
158+
#endif
159+
122160
#define HANDLER_RECOVER(name, kind) \
123161
INTERFACE void __ubsan_handle_##name##_minimal() { \
124162
__ubsan_report_error(kind, GET_CALLER_PC()); \
@@ -133,7 +171,8 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
133171

134172
#define HANDLER(name, kind) \
135173
HANDLER_RECOVER(name, kind) \
136-
HANDLER_NORECOVER(name, kind)
174+
HANDLER_NORECOVER(name, kind) \
175+
HANDLER_PRESERVE(name, kind)
137176

138177
HANDLER(type_mismatch, "type-mismatch")
139178
HANDLER(alignment_assumption, "alignment-assumption")

0 commit comments

Comments
 (0)