https://github.com/tarcisiofischer created https://github.com/llvm/llvm-project/pull/182028
The current behaviour is that any global variable inside sections is not MTE tagged, and (to the best of my knowledge) there's no way to opt-in. This PR proposes a way to opt-in. One example of where this could potentially be useful is the ProtectedMemory class on Chromium, which adds all the "protected" variables inside a single section to control it's access (https://source.chromium.org/chromium/chromium/src/+/main:base/memory/protected_memory.h;l=157;drc=299864be12719dba5dee143363b6aaa150cb96f8). (Reopen from https://github.com/llvm/llvm-project/pull/168535) From d1311b91b47f641fd9979c4f815cff69e0793ca6 Mon Sep 17 00:00:00 2001 From: Tarcisio Fischer <[email protected]> Date: Tue, 18 Nov 2025 13:23:57 +0000 Subject: [PATCH 1/5] [MTE] Add an attribute to opt-in memory tagging of global variables while using fsanitize=memtag-globals (#166380) --- clang/include/clang/Basic/Attr.td | 6 ++++++ clang/include/clang/Basic/AttrDocs.td | 10 ++++++++++ clang/lib/CodeGen/CodeGenModule.cpp | 7 +++++++ clang/lib/CodeGen/CodeGenModule.h | 2 ++ clang/lib/Sema/SemaDeclAttr.cpp | 7 +++++++ clang/test/CodeGen/memtag-globals.cpp | 6 ++++++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 3 ++- 7 files changed, 40 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 2621d178d99e8..680d75bedf5dd 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3927,6 +3927,12 @@ def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetAnyX86> let Documentation = [X86ForceAlignArgPointerDocs]; } +def SectionMemtag : InheritableAttr { + let Spellings = [ClangGCC<"section_memtag">]; + let Subjects = SubjectList<[GlobalVar]>; + let Documentation = [SectionMemtagDocs]; +} + def NoSanitize : InheritableAttr { let Spellings = [ClangGCC<"no_sanitize">]; let Args = [VariadicStringArgument<"Sanitizers">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index f91fe2c7b0259..d9c25f181859b 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3667,6 +3667,16 @@ full list of supported sanitizer flags. }]; } +def SectionMemtagDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +Use the ``section_memtag`` attribute on a global variable declaration that also +has the attribute section and the memory tag sanitizer is active to force the +global variable to be MTE tagged. Global variables under sections are not +tagged by default, so you need to explicitly opt-in using this attribute. + }]; +} + def DisableSanitizerInstrumentationDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 6a087be3751f0..69921abe092c9 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3954,6 +3954,10 @@ bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind, return false; } +bool CodeGenModule::userForcedSectionMemtag(llvm::GlobalVariable *GV) const { + return GV->getMetadata("section_memtag") != nullptr; +} + bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc, StringRef Category) const { const auto &XRayFilter = getContext().getXRayFilter(); @@ -6330,6 +6334,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); + if (D->hasAttr<SectionMemtagAttr>()) { + GV->setMetadata("section_memtag", llvm::MDNode::get(GV->getContext(), {})); + } SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); // Emit global variable debug information. diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 3ed1dd7a57225..8710056d24d54 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1549,6 +1549,8 @@ class CodeGenModule : public CodeGenTypeCache { SourceLocation Loc, QualType Ty, StringRef Category = StringRef()) const; + bool userForcedSectionMemtag(llvm::GlobalVariable *GV) const; + /// Imbue XRay attributes to a function, applying the always/never attribute /// lists in the process. Returns true if we did imbue attributes this way, /// false otherwise. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5dbff18fff7a9..db85daf00187c 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6665,6 +6665,10 @@ static bool isSanitizerAttributeAllowedOnGlobals(StringRef Sanitizer) { Sanitizer == "memtag"; } +static void handleSectionMemtagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + D->addAttr(SectionMemtagAttr::CreateImplicit(S.Context, AL)); +} + static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.checkAtLeastNumArgs(S, 1)) return; @@ -7938,6 +7942,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_PtGuardedVar: handlePtGuardedVarAttr(S, D, AL); break; + case ParsedAttr::AT_SectionMemtag: + handleSectionMemtagAttr(S, D, AL); + break; case ParsedAttr::AT_NoSanitize: handleNoSanitizeAttr(S, D, AL); break; diff --git a/clang/test/CodeGen/memtag-globals.cpp b/clang/test/CodeGen/memtag-globals.cpp index 407eea1c37cfa..74475b5e9a483 100644 --- a/clang/test/CodeGen/memtag-globals.cpp +++ b/clang/test/CodeGen/memtag-globals.cpp @@ -11,6 +11,7 @@ int global; int __attribute__((__section__("my_section"))) section_global; +int __attribute__((__section__("my_section"))) __attribute__((section_memtag)) section_global_tagged; int __attribute__((no_sanitize("memtag"))) attributed_global; int __attribute__((disable_sanitizer_instrumentation)) disable_instrumentation_global; int ignorelisted_global; @@ -28,6 +29,11 @@ void func() { // This DOES NOT mean we are instrumenting the section global, // but we are ignoring it in AsmPrinter rather than in clang. // CHECK: @{{.*}}section_global{{.*}} ={{.*}} sanitize_memtag + +// In order to opt-in memory tagging in globals in sections, +// __attribute__((section_memtag)) must be used. +// CHECK: @{{.*}}section_global_tagged{{.*}} ={{.*}} sanitize_memtag,{{.*}} !section_memtag + // CHECK: @{{.*}}attributed_global{{.*}} = // CHECK-NOT: sanitize_memtag // CHECK: @{{.*}}disable_instrumentation_global{{.*}} = diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index d968ead83e5ed..01234f172e794 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2690,7 +2690,8 @@ static bool shouldTagGlobal(const llvm::GlobalVariable &G) { // To mitigate both these cases, and because specifying a section is rare // outside of these two cases, disable MTE protection for globals in any // section. - if (G.hasSection()) + bool ForceSectionMemtag = G.getMetadata("section_memtag") != nullptr; + if (G.hasSection() && !ForceSectionMemtag) return false; return globalSize(G) > 0; From 78cd82091ecb63237624e11e88b74df52fd5098a Mon Sep 17 00:00:00 2001 From: Tarcisio Fischer <[email protected]> Date: Mon, 1 Dec 2025 11:40:10 +0000 Subject: [PATCH 2/5] Rename section to 'force_memtag' and fix tests --- clang/include/clang/Basic/Attr.td | 6 +++--- clang/include/clang/Basic/AttrDocs.td | 4 ++-- clang/lib/CodeGen/CodeGenModule.cpp | 6 +++--- clang/lib/Sema/SemaDeclAttr.cpp | 8 ++++---- clang/test/CodeGen/memtag-globals-asm.cpp | 2 ++ clang/test/CodeGen/memtag-globals.cpp | 6 +++--- .../Misc/pragma-attribute-supported-attributes-list.test | 1 + llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 +- 8 files changed, 19 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 680d75bedf5dd..1791ef5908742 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3927,10 +3927,10 @@ def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetAnyX86> let Documentation = [X86ForceAlignArgPointerDocs]; } -def SectionMemtag : InheritableAttr { - let Spellings = [ClangGCC<"section_memtag">]; +def ForceMemtag : InheritableAttr { + let Spellings = [ClangGCC<"force_memtag">]; let Subjects = SubjectList<[GlobalVar]>; - let Documentation = [SectionMemtagDocs]; + let Documentation = [ForceMemtagDocs]; } def NoSanitize : InheritableAttr { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index d9c25f181859b..5cb1618923a9e 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3667,10 +3667,10 @@ full list of supported sanitizer flags. }]; } -def SectionMemtagDocs : Documentation { +def ForceMemtagDocs : Documentation { let Category = DocCatVariable; let Content = [{ -Use the ``section_memtag`` attribute on a global variable declaration that also +Use the ``force_memtag`` attribute on a global variable declaration that also has the attribute section and the memory tag sanitizer is active to force the global variable to be MTE tagged. Global variables under sections are not tagged by default, so you need to explicitly opt-in using this attribute. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 69921abe092c9..a62f6c81ed3a2 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3955,7 +3955,7 @@ bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind, } bool CodeGenModule::userForcedSectionMemtag(llvm::GlobalVariable *GV) const { - return GV->getMetadata("section_memtag") != nullptr; + return GV->getMetadata("force_memtag") != nullptr; } bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc, @@ -6334,8 +6334,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); - if (D->hasAttr<SectionMemtagAttr>()) { - GV->setMetadata("section_memtag", llvm::MDNode::get(GV->getContext(), {})); + if (D->hasAttr<ForceMemtagAttr>()) { + GV->setMetadata("force_memtag", llvm::MDNode::get(GV->getContext(), {})); } SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index db85daf00187c..06ff06460bfdb 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6665,8 +6665,8 @@ static bool isSanitizerAttributeAllowedOnGlobals(StringRef Sanitizer) { Sanitizer == "memtag"; } -static void handleSectionMemtagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - D->addAttr(SectionMemtagAttr::CreateImplicit(S.Context, AL)); +static void handleForceMemtagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + D->addAttr(ForceMemtagAttr::CreateImplicit(S.Context, AL)); } static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -7942,8 +7942,8 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_PtGuardedVar: handlePtGuardedVarAttr(S, D, AL); break; - case ParsedAttr::AT_SectionMemtag: - handleSectionMemtagAttr(S, D, AL); + case ParsedAttr::AT_ForceMemtag: + handleForceMemtagAttr(S, D, AL); break; case ParsedAttr::AT_NoSanitize: handleNoSanitizeAttr(S, D, AL); diff --git a/clang/test/CodeGen/memtag-globals-asm.cpp b/clang/test/CodeGen/memtag-globals-asm.cpp index fb3958dd8bcb6..eb62523ce7cc9 100644 --- a/clang/test/CodeGen/memtag-globals-asm.cpp +++ b/clang/test/CodeGen/memtag-globals-asm.cpp @@ -292,6 +292,7 @@ CONSTRUCTOR(".preinit_array") func_t preinit_array = func_constructor; CONSTRUCTOR("array_of_globals") int global1; CONSTRUCTOR("array_of_globals") int global2; CONSTRUCTOR("array_of_globals") int global_string; +CONSTRUCTOR("opt_in_memtag") __attribute__((force_memtag)) int tagged_global; // CHECK-NOT: .memtag func_constructor // CHECK-NOT: .memtag func_init @@ -304,3 +305,4 @@ CONSTRUCTOR("array_of_globals") int global_string; // CHECK-NOT: .memtag global1 // CHECK-NOT: .memtag global2 // CHECK-NOT: .memtag global_string +// CHECK: .memtag tagged_global diff --git a/clang/test/CodeGen/memtag-globals.cpp b/clang/test/CodeGen/memtag-globals.cpp index 74475b5e9a483..4fa45a65b58de 100644 --- a/clang/test/CodeGen/memtag-globals.cpp +++ b/clang/test/CodeGen/memtag-globals.cpp @@ -11,7 +11,7 @@ int global; int __attribute__((__section__("my_section"))) section_global; -int __attribute__((__section__("my_section"))) __attribute__((section_memtag)) section_global_tagged; +int __attribute__((__section__("my_section"))) __attribute__((force_memtag)) section_global_tagged; int __attribute__((no_sanitize("memtag"))) attributed_global; int __attribute__((disable_sanitizer_instrumentation)) disable_instrumentation_global; int ignorelisted_global; @@ -31,8 +31,8 @@ void func() { // CHECK: @{{.*}}section_global{{.*}} ={{.*}} sanitize_memtag // In order to opt-in memory tagging in globals in sections, -// __attribute__((section_memtag)) must be used. -// CHECK: @{{.*}}section_global_tagged{{.*}} ={{.*}} sanitize_memtag,{{.*}} !section_memtag +// __attribute__((force_memtag)) must be used. +// CHECK: @{{.*}}section_global_tagged{{.*}} ={{.*}} sanitize_memtag,{{.*}} !force_memtag // CHECK: @{{.*}}attributed_global{{.*}} = // CHECK-NOT: sanitize_memtag diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 626a0743238d5..cca875f722292 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -86,6 +86,7 @@ // CHECK-NEXT: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) // CHECK-NEXT: FlagEnum (SubjectMatchRule_enum) // CHECK-NEXT: Flatten (SubjectMatchRule_function) +// CHECK-NEXT: ForceMemtag (SubjectMatchRule_variable_is_global) // CHECK-NEXT: FunctionReturnThunks (SubjectMatchRule_function) // CHECK-NEXT: GCCStruct (SubjectMatchRule_record) // CHECK-NEXT: GNUInline (SubjectMatchRule_function) diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 01234f172e794..685490541b714 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2690,7 +2690,7 @@ static bool shouldTagGlobal(const llvm::GlobalVariable &G) { // To mitigate both these cases, and because specifying a section is rare // outside of these two cases, disable MTE protection for globals in any // section. - bool ForceSectionMemtag = G.getMetadata("section_memtag") != nullptr; + bool ForceSectionMemtag = G.getMetadata("force_memtag") != nullptr; if (G.hasSection() && !ForceSectionMemtag) return false; From 375c446eeb6b13c9dbd2df2293f98678206bd22b Mon Sep 17 00:00:00 2001 From: Tarcisio Fischer <[email protected]> Date: Fri, 5 Dec 2025 11:41:03 +0000 Subject: [PATCH 3/5] Improve docs and fix code style --- clang/include/clang/Basic/AttrDocs.td | 6 ++++-- clang/lib/CodeGen/CodeGenModule.cpp | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 5cb1618923a9e..c6035cb1e5d25 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3671,9 +3671,11 @@ def ForceMemtagDocs : Documentation { let Category = DocCatVariable; let Content = [{ Use the ``force_memtag`` attribute on a global variable declaration that also -has the attribute section and the memory tag sanitizer is active to force the -global variable to be MTE tagged. Global variables under sections are not +has the attribute section. If the memory tag sanitizer is active, will force +the global variable to be MTE tagged. Global variables under sections are not tagged by default, so you need to explicitly opt-in using this attribute. +Please note that, unfortunately, in some non-trivial cases where memory layout +is assumed, forcing enabling the memtag will cause SIGSEGV/MTE[AS]ERR. }]; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a62f6c81ed3a2..4e784adb726e9 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -6334,9 +6334,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); - if (D->hasAttr<ForceMemtagAttr>()) { + if (D->hasAttr<ForceMemtagAttr>()) GV->setMetadata("force_memtag", llvm::MDNode::get(GV->getContext(), {})); - } SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); // Emit global variable debug information. From 4b370ff22b3e0b5c8ceaab8e51777aa757d0f5da Mon Sep 17 00:00:00 2001 From: Tarcisio Fischer <[email protected]> Date: Mon, 8 Dec 2025 09:55:32 +0000 Subject: [PATCH 4/5] Fix documentation --- clang/include/clang/Basic/AttrDocs.td | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index c6035cb1e5d25..34bf91c6ab954 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3674,8 +3674,9 @@ Use the ``force_memtag`` attribute on a global variable declaration that also has the attribute section. If the memory tag sanitizer is active, will force the global variable to be MTE tagged. Global variables under sections are not tagged by default, so you need to explicitly opt-in using this attribute. -Please note that, unfortunately, in some non-trivial cases where memory layout -is assumed, forcing enabling the memtag will cause SIGSEGV/MTE[AS]ERR. +Please note that, unfortunately, in non-trivial cases where memory layout +is assumed, forcing memory tagging might lead to extremely hard to debug bugs, +depending on what the code assuming the alignment does. }]; } From 5a046acbb17f8970406be5af695f3bc1284d2e68 Mon Sep 17 00:00:00 2001 From: Tarcisio Fischer <[email protected]> Date: Wed, 18 Feb 2026 13:40:22 +0000 Subject: [PATCH 5/5] Move ForceMemtag to SanitizerMetadata Also avoid tagged variables to be put in ro regions. --- clang/lib/CodeGen/CodeGenModule.cpp | 6 ------ clang/lib/CodeGen/CodeGenModule.h | 2 -- clang/lib/CodeGen/SanitizerMetadata.cpp | 6 ++++-- clang/lib/CodeGen/SanitizerMetadata.h | 3 ++- clang/test/CodeGen/memtag-globals.cpp | 5 ----- llvm/include/llvm/IR/GlobalValue.h | 13 ++++++++++--- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 7 +++++-- llvm/lib/Target/TargetLoweringObjectFile.cpp | 6 ++++++ 8 files changed, 27 insertions(+), 21 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 4e784adb726e9..6a087be3751f0 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3954,10 +3954,6 @@ bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind, return false; } -bool CodeGenModule::userForcedSectionMemtag(llvm::GlobalVariable *GV) const { - return GV->getMetadata("force_memtag") != nullptr; -} - bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc, StringRef Category) const { const auto &XRayFilter = getContext().getXRayFilter(); @@ -6334,8 +6330,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); - if (D->hasAttr<ForceMemtagAttr>()) - GV->setMetadata("force_memtag", llvm::MDNode::get(GV->getContext(), {})); SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor); // Emit global variable debug information. diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 8710056d24d54..3ed1dd7a57225 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1549,8 +1549,6 @@ class CodeGenModule : public CodeGenTypeCache { SourceLocation Loc, QualType Ty, StringRef Category = StringRef()) const; - bool userForcedSectionMemtag(llvm::GlobalVariable *GV) const; - /// Imbue XRay attributes to a function, applying the always/never attribute /// lists in the process. Returns true if we did imbue attributes this way, /// false otherwise. diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index 288f7f6415f44..d9fc20e4bdf0f 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -36,7 +36,8 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc, StringRef Name, QualType Ty, SanitizerMask NoSanitizeAttrMask, - bool IsDynInit) { + bool IsDynInit, + bool HasForcedSanitizeMemtag) { SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize; if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument)) return; @@ -63,6 +64,7 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag); Meta.Memtag &= !CGM.isInNoSanitizeList( FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty); + Meta.ForceMemtag |= HasForcedSanitizeMemtag; Meta.IsDynInit = IsDynInit && !Meta.NoAddress && FsanitizeArgument.has(SanitizerKind::Address) && @@ -119,7 +121,7 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D, }; reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D), - IsDynInit); + IsDynInit, D.hasAttr<ForceMemtagAttr>()); } void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) { diff --git a/clang/lib/CodeGen/SanitizerMetadata.h b/clang/lib/CodeGen/SanitizerMetadata.h index 000f02cf8dcf1..20627991e051b 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.h +++ b/clang/lib/CodeGen/SanitizerMetadata.h @@ -42,7 +42,8 @@ class SanitizerMetadata { void reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc, StringRef Name, QualType Ty = {}, SanitizerMask NoSanitizeAttrMask = {}, - bool IsDynInit = false); + bool IsDynInit = false, + bool HasForcedSanitizeMemtag = false); void disableSanitizerForGlobal(llvm::GlobalVariable *GV); }; } // end namespace CodeGen diff --git a/clang/test/CodeGen/memtag-globals.cpp b/clang/test/CodeGen/memtag-globals.cpp index 4fa45a65b58de..5743e608111ad 100644 --- a/clang/test/CodeGen/memtag-globals.cpp +++ b/clang/test/CodeGen/memtag-globals.cpp @@ -11,7 +11,6 @@ int global; int __attribute__((__section__("my_section"))) section_global; -int __attribute__((__section__("my_section"))) __attribute__((force_memtag)) section_global_tagged; int __attribute__((no_sanitize("memtag"))) attributed_global; int __attribute__((disable_sanitizer_instrumentation)) disable_instrumentation_global; int ignorelisted_global; @@ -30,10 +29,6 @@ void func() { // but we are ignoring it in AsmPrinter rather than in clang. // CHECK: @{{.*}}section_global{{.*}} ={{.*}} sanitize_memtag -// In order to opt-in memory tagging in globals in sections, -// __attribute__((force_memtag)) must be used. -// CHECK: @{{.*}}section_global_tagged{{.*}} ={{.*}} sanitize_memtag,{{.*}} !force_memtag - // CHECK: @{{.*}}attributed_global{{.*}} = // CHECK-NOT: sanitize_memtag // CHECK: @{{.*}}disable_instrumentation_global{{.*}} = diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h index 83e695cdd27d9..f1492b90dc014 100644 --- a/llvm/include/llvm/IR/GlobalValue.h +++ b/llvm/include/llvm/IR/GlobalValue.h @@ -318,8 +318,8 @@ class GlobalValue : public Constant { // specifically to global variables. struct SanitizerMetadata { SanitizerMetadata() - : NoAddress(false), NoHWAddress(false), - Memtag(false), IsDynInit(false) {} + : NoAddress(false), NoHWAddress(false), Memtag(false), + ForceMemtag(false), IsDynInit(false) {} // For ASan and HWASan, this instrumentation is implicitly applied to all // global variables when built with -fsanitize=*. What we need is a way to // persist the information that a certain global variable should *not* have @@ -346,7 +346,13 @@ class GlobalValue : public Constant { // // Use `GlobalValue::isTagged()` to check whether tagging should be enabled // for a global variable. + // + // Since not all global variables will be tagged (more specifically, + // variables inside sections will not be tagged), ForceMemtag can be used + // to opt-in memory taggig in those cases. For more information see + // __attribute__((force_memtag)). unsigned Memtag : 1; + unsigned ForceMemtag : 1; // ASan-specific metadata. Is this global variable dynamically initialized // (from a C++ language perspective), and should therefore be checked for @@ -365,7 +371,8 @@ class GlobalValue : public Constant { LLVM_ABI void setNoSanitizeMetadata(); bool isTagged() const { - return hasSanitizerMetadata() && getSanitizerMetadata().Memtag; + return hasSanitizerMetadata() && (getSanitizerMetadata().Memtag || + getSanitizerMetadata().ForceMemtag); } static LinkageTypes getLinkOnceLinkage(bool ODR) { diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 685490541b714..df380efc0497c 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2662,6 +2662,10 @@ static uint64_t globalSize(const llvm::GlobalVariable &G) { } static bool shouldTagGlobal(const llvm::GlobalVariable &G) { + auto Meta = G.getSanitizerMetadata(); + if (Meta.ForceMemtag) + return true; + // We used to do this in clang, but there are optimization passes that turn // non-constant globals into constants. So now, clang only tells us whether // it would *like* a global to be tagged, but we still make the decision here. @@ -2690,8 +2694,7 @@ static bool shouldTagGlobal(const llvm::GlobalVariable &G) { // To mitigate both these cases, and because specifying a section is rare // outside of these two cases, disable MTE protection for globals in any // section. - bool ForceSectionMemtag = G.getMetadata("force_memtag") != nullptr; - if (G.hasSection() && !ForceSectionMemtag) + if (G.hasSection()) return false; return globalSize(G) > 0; diff --git a/llvm/lib/Target/TargetLoweringObjectFile.cpp b/llvm/lib/Target/TargetLoweringObjectFile.cpp index ae31cd90b37ab..bf26656314dc3 100644 --- a/llvm/lib/Target/TargetLoweringObjectFile.cpp +++ b/llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -298,6 +298,12 @@ SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalObject *GO, // If the global is marked constant, we can put it into a mergable section, // a mergable string section, or general .data if it contains relocations. if (GVar->isConstant()) { + if (GVar->hasSanitizerMetadata()) { + auto Meta = GVar->getSanitizerMetadata(); + if (Meta.ForceMemtag) + return SectionKind::getData(); + } + // If the initializer for the global contains something that requires a // relocation, then we may have to drop this into a writable data section // even though it is marked const. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
