Skip to content

Commit 90e5a8a

Browse files
committed
Remove 'no_sanitize_memtag'. Add 'sanitize_memtag'.
For MTE globals, we should have clang emit the attribute for all GV's that it creates, and then use that in the upcoming AArch64 global tagging IR pass. We need a positive attribute for this sanitizer (rather than implicit sanitization of all globals) because it needs to interact with other parts of LLVM, including: 1. Suppressing certain global optimisations (like merging), 2. Emitting extra directives by the ASM writer, and 3. Putting extra information in the symbol table entries. While this does technically make the LLVM IR / bitcode format non-backwards-compatible, nobody should have used this attribute yet, because it's a no-op. Reviewed By: eugenis Differential Revision: https://reviews.llvm.org/D128950
1 parent 4f281fa commit 90e5a8a

File tree

12 files changed

+95
-76
lines changed

12 files changed

+95
-76
lines changed

clang/lib/CodeGen/SanitizerMetadata.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
6060
Meta.NoHWAddress |= CGM.isInNoSanitizeList(
6161
FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty);
6262

63-
Meta.NoMemtag |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
64-
Meta.NoMemtag |= CGM.isInNoSanitizeList(
63+
Meta.Memtag |=
64+
static_cast<bool>(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals);
65+
Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
66+
Meta.Memtag &= !CGM.isInNoSanitizeList(
6567
FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty);
6668

6769
Meta.IsDynInit = IsDynInit && !Meta.NoAddress &&

clang/test/CodeGen/memtag-globals.cpp

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,30 @@ void func() {
1717
const char *literal = "Hello, world!";
1818
}
1919

20-
// CHECK: @{{.*}}extra_global{{.*}} =
21-
// CHECK-NOT: no_sanitize_memtag
22-
// CHECK: @{{.*}}global{{.*}} =
23-
// CHECK-NOT: no_sanitize_memtag
24-
// CHECK: @{{.*}}attributed_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag
25-
// CHECK: @{{.*}}disable_instrumentation_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag
26-
// CHECK: @{{.*}}ignorelisted_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag
27-
// CHECK: @{{.*}}static_var{{.*}} =
28-
// CHECK-NOT: no_sanitize_memtag
29-
// CHECK: @{{.*}} = {{.*}} c"Hello, world!\00"
30-
// CHECK-NOT: no_sanitize_memtag
31-
32-
// IGNORELIST: @{{.*}}extra_global{{.*}} ={{.*}} global
33-
// IGNORELIST-NOT: no_sanitize_memtag
34-
// IGNORELIST: @{{.*}}global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag
35-
// IGNORELIST: @{{.*}}attributed_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag
36-
// IGNORELIST: @{{.*}}disable_instrumentation_global{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag
37-
// IGNORELIST: @{{.*}}ignorelisted_globa{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag
38-
// IGNORELIST: @{{.*}}static_var{{.*}} ={{.*}} global {{.*}}, no_sanitize_memtag
39-
// IGNORELIST: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}}, no_sanitize_memtag
20+
// CHECK: @{{.*}}extra_global{{.*}} ={{.*}} sanitize_memtag
21+
// CHECK: @{{.*}}global{{.*}} ={{.*}} sanitize_memtag
22+
23+
// CHECK: @{{.*}}attributed_global{{.*}} =
24+
// CHECK-NOT: sanitize_memtag
25+
// CHECK: @{{.*}}disable_instrumentation_global{{.*}} =
26+
// CHECK-NOT: sanitize_memtag
27+
// CHECK: @{{.*}}ignorelisted_global{{.*}} =
28+
// CHECK-NOT: sanitize_memtag
29+
30+
// CHECK: @{{.*}}static_var{{.*}} ={{.*}} sanitize_memtag
31+
// CHECK: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}} sanitize_memtag
32+
33+
// IGNORELIST: @{{.*}}extra_global{{.*}} ={{.*}} sanitize_memtag
34+
35+
// IGNORELIST: @{{.*}}global{{.*}} =
36+
// IGNORELIST-NOT: sanitize_memtag
37+
// IGNORELIST: @{{.*}}attributed_global{{.*}} =
38+
// IGNORELIST-NOT: sanitize_memtag
39+
// IGNORELIST: @{{.*}}disable_instrumentation_global{{.*}} =
40+
// IGNORELIST-NOT: sanitize_memtag
41+
// IGNORELIST: @{{.*}}ignorelisted_globa{{.*}} =
42+
// IGNORELIST-NOT: sanitize_memtag
43+
// IGNORELIST: @{{.*}}static_var{{.*}} =
44+
// IGNORELIST-NOT: sanitize_memtag
45+
// IGNORELIST: @{{.*}} = {{.*}} c"Hello, world!\00"{{.*}}
46+
// IGNORELIST-NOT: sanitize_memtag

clang/test/CodeGen/sanitizer-special-case-list-globals.c

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@
1717
// RUN: -fsanitize-ignorelist=%S/Inputs/sanitizer-special-case-list-globals.txt \
1818
// RUN: | FileCheck %s --check-prefix=HWASAN
1919

20-
/// TODO(hctim): Move over to memtag-globals when it's implemented. For now
21-
/// though, it's fine, the frontend still annotates based on any memtag sanitizer
22-
/// being used.
23-
// RUN: %clang_cc1 -fsanitize=memtag-heap -triple=aarch64-linux-android31 -emit-llvm %s -o -\
20+
// RUN: %clang_cc1 -fsanitize=memtag-globals -triple=aarch64-linux-android31 \
2421
// RUN: -fsanitize-ignorelist=%S/Inputs/sanitizer-special-case-list-globals.txt \
25-
// RUN: | FileCheck %s --check-prefix=MEMTAG
22+
// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=MEMTAG
2623

2724
/// Check that the '[cfi-vcall|cfi-icall] src:*' rule in the ignorelist doesn't change
2825
/// anything for ASan.
@@ -46,29 +43,28 @@
4643
// RUN: -fsanitize-ignorelist=%S/Inputs/sanitizer-special-case-list-globals.txt \
4744
// RUN: | FileCheck %s --check-prefix=NONE
4845

49-
// NONE: @always_ignored ={{.*}} global
50-
// NONE-NOT: no_sanitize
51-
// ASAN: @always_ignored ={{.*}} global {{.*}}, no_sanitize_address
52-
// HWASAN: @always_ignored ={{.*}} global {{.*}}, no_sanitize_hwaddress
53-
// MEMTAG: @always_ignored ={{.*}} global {{.*}}, no_sanitize_memtag
46+
// NONE: @always_ignored ={{.*}} global
47+
// NONE-NOT: no_sanitize
48+
// ASAN: @always_ignored ={{.*}} global {{.*}}, no_sanitize_address
49+
// HWASAN: @always_ignored ={{.*}} global {{.*}}, no_sanitize_hwaddress
50+
// MEMTAG: @always_ignored ={{.*}} global
51+
// MEMTAG-NOT: sanitize_memtag
5452
unsigned always_ignored;
5553

5654
// NONE: @hwasan_ignored ={{.*}} global
5755
// NONE-NOT: no_sanitize
5856
// ASAN: @hwasan_ignored ={{.*}} global
5957
// ASAN-NOT: no_sanitize_address
6058
// HWASAN: @hwasan_ignored ={{.*}} global {{.*}}, no_sanitize_hwaddress
61-
// MEMTAG: @hwasan_ignored ={{.*}} global
62-
// MEMTAG-NOT: no_sanitize_memtag
59+
// MEMTAG: @hwasan_ignored ={{.*}} global {{.*}} sanitize_memtag
6360
unsigned hwasan_ignored;
6461

6562
// NONE: @asan_ignored ={{.*}} global
6663
// NONE-NOT: asan_ignored
6764
// ASAN: @asan_ignored ={{.*}} global {{.*}}, no_sanitize_address
6865
// HWASAN: @asan_ignored.hwasan = {{.*}} global
6966
// HWASAN-NOT: no_sanitize_hwaddress
70-
// MEMTAG: @asan_ignored ={{.*}} global
71-
// MEMTAG-NOT: no_sanitize_memtag
67+
// MEMTAG: @asan_ignored ={{.*}} global {{.*}} sanitize_memtag
7268
unsigned asan_ignored;
7369

7470
// NONE: @memtag_ignored ={{.*}} global
@@ -77,7 +73,8 @@ unsigned asan_ignored;
7773
// ASAN-NOT: no_sanitize_address
7874
// HWASAN: @memtag_ignored.hwasan = {{.*}} global
7975
// HWASAN-NOT: no_sanitize_hwaddress
80-
// MEMTAG: @memtag_ignored ={{.*}} global {{.*}}, no_sanitize_memtag
76+
// MEMTAG: @memtag_ignored ={{.*}} global
77+
// MEMTAG-NOT: sanitize_memtag
8178
unsigned memtag_ignored;
8279

8380
// NONE: @never_ignored ={{.*}} global
@@ -86,6 +83,5 @@ unsigned memtag_ignored;
8683
// ASAN-NOT: no_sanitize_address
8784
// HWASAN: @never_ignored.hwasan ={{.*}} global
8885
// HWASAN-NOT: no_sanitize_hwaddress
89-
// MEMTAG: @never_ignored ={{.*}} global
90-
// MEMTAG-NOT: no_sanitize_memtag
86+
// MEMTAG: @never_ignored ={{.*}} global {{.*}} sanitize_memtag
9187
unsigned never_ignored;

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,6 @@ enum Kind {
399399
// GV's with __attribute__((no_sanitize("hwaddress"))), or things in
400400
// -fsanitize-ignorelist when built with HWASan.
401401
kw_no_sanitize_hwaddress,
402-
// GV's with __attribute__((no_sanitize("memtag"))), or things in
403-
// -fsanitize-ignorelist when built with memory tagging.
404-
kw_no_sanitize_memtag,
405402
// GV's where the clang++ frontend (when ASan is used) notes that this is
406403
// dynamically initialized, and thus needs ODR detection.
407404
kw_sanitize_address_dyninit,

llvm/include/llvm/IR/GlobalValue.h

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -295,26 +295,38 @@ class GlobalValue : public Constant {
295295
void setPartition(StringRef Part);
296296

297297
// ASan, HWASan and Memtag sanitizers have some instrumentation that applies
298-
// specifically to global variables. This instrumentation is implicitly
299-
// applied to all global variables when built with -fsanitize=*. What we need
300-
// is a way to persist the information that a certain global variable should
301-
// *not* have sanitizers applied, which occurs if:
302-
// 1. The global variable is in the sanitizer ignore list, or
303-
// 2. The global variable is created by the sanitizers itself for internal
304-
// usage, or
305-
// 3. The global variable has __attribute__((no_sanitize("..."))) or
306-
// __attribute__((disable_sanitizer_instrumentation)).
307-
//
308-
// This is important, a some IR passes like GlobalMerge can delete global
309-
// variables and replace them with new ones. If the old variables were marked
310-
// to be unsanitized, then the new ones should also be.
298+
// specifically to global variables.
311299
struct SanitizerMetadata {
312300
SanitizerMetadata()
313-
: NoAddress(false), NoHWAddress(false), NoMemtag(false),
314-
IsDynInit(false) {}
301+
: NoAddress(false), NoHWAddress(false),
302+
Memtag(false), IsDynInit(false) {}
303+
// For ASan and HWASan, this instrumentation is implicitly applied to all
304+
// global variables when built with -fsanitize=*. What we need is a way to
305+
// persist the information that a certain global variable should *not* have
306+
// sanitizers applied, which occurs if:
307+
// 1. The global variable is in the sanitizer ignore list, or
308+
// 2. The global variable is created by the sanitizers itself for internal
309+
// usage, or
310+
// 3. The global variable has __attribute__((no_sanitize("..."))) or
311+
// __attribute__((disable_sanitizer_instrumentation)).
312+
//
313+
// This is important, a some IR passes like GlobalMerge can delete global
314+
// variables and replace them with new ones. If the old variables were
315+
// marked to be unsanitized, then the new ones should also be.
315316
unsigned NoAddress : 1;
316317
unsigned NoHWAddress : 1;
317-
unsigned NoMemtag : 1;
318+
319+
// Memtag sanitization works differently: sanitization is requested by clang
320+
// when `-fsanitize=memtag-globals` is provided, and the request can be
321+
// denied (and the attribute removed) by the AArch64 global tagging pass if
322+
// it can't be fulfilled (e.g. the global variable is a TLS variable).
323+
// Memtag sanitization has to interact with other parts of LLVM (like
324+
// supressing certain optimisations, emitting assembly directives, or
325+
// creating special relocation sections).
326+
//
327+
// Use `GlobalValue::isTagged()` to check whether tagging should be enabled
328+
// for a global variable.
329+
unsigned Memtag : 1;
318330

319331
// ASan-specific metadata. Is this global variable dynamically initialized
320332
// (from a C++ language perspective), and should therefore be checked for
@@ -331,6 +343,10 @@ class GlobalValue : public Constant {
331343
void setSanitizerMetadata(SanitizerMetadata Meta);
332344
void removeSanitizerMetadata();
333345

346+
bool isTagged() const {
347+
return hasSanitizerMetadata() && getSanitizerMetadata().Memtag;
348+
}
349+
334350
static LinkageTypes getLinkOnceLinkage(bool ODR) {
335351
return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage;
336352
}

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,6 @@ lltok::Kind LLLexer::LexIdentifier() {
582582

583583
KEYWORD(no_sanitize_address);
584584
KEYWORD(no_sanitize_hwaddress);
585-
KEYWORD(no_sanitize_memtag);
586585
KEYWORD(sanitize_address_dyninit);
587586

588587
KEYWORD(ccc);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@ static bool isSanitizer(lltok::Kind Kind) {
11121112
switch (Kind) {
11131113
case lltok::kw_no_sanitize_address:
11141114
case lltok::kw_no_sanitize_hwaddress:
1115-
case lltok::kw_no_sanitize_memtag:
1115+
case lltok::kw_sanitize_memtag:
11161116
case lltok::kw_sanitize_address_dyninit:
11171117
return true;
11181118
default:
@@ -1133,8 +1133,8 @@ bool LLParser::parseSanitizer(GlobalVariable *GV) {
11331133
case lltok::kw_no_sanitize_hwaddress:
11341134
Meta.NoHWAddress = true;
11351135
break;
1136-
case lltok::kw_no_sanitize_memtag:
1137-
Meta.NoMemtag = true;
1136+
case lltok::kw_sanitize_memtag:
1137+
Meta.Memtag = true;
11381138
break;
11391139
case lltok::kw_sanitize_address_dyninit:
11401140
Meta.IsDynInit = true;

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3678,7 +3678,7 @@ GlobalValue::SanitizerMetadata deserializeSanitizerMetadata(unsigned V) {
36783678
if (V & (1 << 1))
36793679
Meta.NoHWAddress = true;
36803680
if (V & (1 << 2))
3681-
Meta.NoMemtag = true;
3681+
Meta.Memtag = true;
36823682
if (V & (1 << 3))
36833683
Meta.IsDynInit = true;
36843684
return Meta;

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,7 @@ static_assert(sizeof(GlobalValue::SanitizerMetadata) <= sizeof(unsigned),
12341234
static unsigned
12351235
serializeSanitizerMetadata(const GlobalValue::SanitizerMetadata &Meta) {
12361236
return Meta.NoAddress | (Meta.NoHWAddress << 1) |
1237-
(Meta.NoMemtag << 2) | (Meta.IsDynInit << 3);
1237+
(Meta.Memtag << 2) | (Meta.IsDynInit << 3);
12381238
}
12391239

12401240
/// Emit top-level description of module, including target triple, inline asm,

llvm/lib/IR/AsmWriter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3538,8 +3538,8 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
35383538
Out << ", no_sanitize_address";
35393539
if (MD.NoHWAddress)
35403540
Out << ", no_sanitize_hwaddress";
3541-
if (MD.NoMemtag)
3542-
Out << ", no_sanitize_memtag";
3541+
if (MD.Memtag)
3542+
Out << ", sanitize_memtag";
35433543
if (MD.IsDynInit)
35443544
Out << ", sanitize_address_dyninit";
35453545
}

llvm/test/Assembler/globalvariable-attributes.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
@g4 = global i32 2, align 4 "key5" = "value5" #0
77
@g5 = global i32 2, no_sanitize_address, align 4
88
@g6 = global i32 2, no_sanitize_hwaddress, align 4
9-
@g7 = global i32 2, no_sanitize_memtag, align 4
10-
@g8 = global i32 2, sanitize_address_dyninit, align 4
11-
@g9 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, no_sanitize_memtag, align 4
9+
@g7 = global i32 2, sanitize_address_dyninit, align 4
10+
@g8 = global i32 2, sanitize_memtag, align 4
11+
@g9 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, sanitize_memtag, align 4
1212

1313
attributes #0 = { "string" = "value" nobuiltin norecurse }
1414

@@ -18,9 +18,9 @@ attributes #0 = { "string" = "value" nobuiltin norecurse }
1818
; CHECK: @g4 = global i32 2, align 4 #3
1919
; CHECK: @g5 = global i32 2, no_sanitize_address, align 4
2020
; CHECK: @g6 = global i32 2, no_sanitize_hwaddress, align 4
21-
; CHECK: @g7 = global i32 2, no_sanitize_memtag, align 4
22-
; CHECK: @g8 = global i32 2, sanitize_address_dyninit, align 4
23-
; CHECK: @g9 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, no_sanitize_memtag, align 4
21+
; CHECK: @g7 = global i32 2, sanitize_address_dyninit, align 4
22+
; CHECK: @g8 = global i32 2, sanitize_memtag, align 4
23+
; CHECK: @g9 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, sanitize_memtag, align 4
2424

2525
; CHECK: attributes #0 = { "key"="value" "key2"="value2" }
2626
; CHECK: attributes #1 = { "key3"="value3" }

llvm/test/Bitcode/compatibility.ll

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,16 @@ declare void @g.f1()
206206
; Global Variables -- sanitizers
207207
@g.no_sanitize_address = global i32 0, no_sanitize_address
208208
@g.no_sanitize_hwaddress = global i32 0, no_sanitize_hwaddress
209-
@g.no_sanitize_memtag = global i32 0, no_sanitize_memtag
210-
@g.no_sanitize_multiple = global i32 0, no_sanitize_address, no_sanitize_hwaddress, no_sanitize_memtag
209+
@g.sanitize_memtag = global i32 0, sanitize_memtag
210+
@g.no_sanitize_multiple = global i32 0, no_sanitize_address, no_sanitize_hwaddress
211211
@g.sanitize_address_dyninit = global i32 0, sanitize_address_dyninit
212+
@g.sanitize_multiple = global i32 0, sanitize_memtag, sanitize_address_dyninit
212213
; CHECK: @g.no_sanitize_address = global i32 0, no_sanitize_address
213214
; CHECK: @g.no_sanitize_hwaddress = global i32 0, no_sanitize_hwaddress
214-
; CHECK: @g.no_sanitize_memtag = global i32 0, no_sanitize_memtag
215-
; CHECK: @g.no_sanitize_multiple = global i32 0, no_sanitize_address, no_sanitize_hwaddress, no_sanitize_memtag
215+
; CHECK: @g.sanitize_memtag = global i32 0, sanitize_memtag
216+
; CHECK: @g.no_sanitize_multiple = global i32 0, no_sanitize_address, no_sanitize_hwaddress
216217
; CHECK: @g.sanitize_address_dyninit = global i32 0, sanitize_address_dyninit
218+
; CHECK: @g.sanitize_multiple = global i32 0, sanitize_memtag, sanitize_address_dyninit
217219

218220
;; Aliases
219221
; Format: @<Name> = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal]

0 commit comments

Comments
 (0)