Skip to content

Conversation

Il-Capitano
Copy link
Contributor

Support for execute-only code generation (#125687) introduced a bug in the case where the memtag sanitizer is used in a module containing a mix of execute-only and non-execute-only functions.

The bug is caused by using return instead of break to short-circuit a loop, which meant that the rest of the function dealing with memtag sanitizer logic wasn't run.

Support for execute-only code generation (llvm#125687) introduced a bug in
the case where the memtag sanitizer is used in a module containing a mix
of execute-only and non-execute-only functions.

The bug is caused by using `return` instead of `break` to short-circuit
a loop, which meant that the rest of the function dealing with memtag
sanitizer logic wasn't run.
@llvmbot llvmbot added backend:AArch64 llvm:mc Machine (object) code labels Mar 26, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 26, 2025

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-mc

Author: Csanád Hajdú (Il-Capitano)

Changes

Support for execute-only code generation (#125687) introduced a bug in the case where the memtag sanitizer is used in a module containing a mix of execute-only and non-execute-only functions.

The bug is caused by using return instead of break to short-circuit a loop, which meant that the rest of the function dealing with memtag sanitizer logic wasn't run.


Full diff: https://github.com/llvm/llvm-project/pull/133084.diff

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp (+11-5)
  • (added) llvm/test/MC/AArch64/execute-only-memtag.ll (+18)
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index 98bd102d8f4c1..b12a12436db81 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
@@ -511,11 +511,17 @@ void AArch64TargetELFStreamer::finish() {
       })) {
     auto *Text =
         static_cast<MCSectionELF *>(Ctx.getObjectFileInfo()->getTextSection());
-    for (auto &F : *Text)
-      if (auto *DF = dyn_cast<MCDataFragment>(&F))
-        if (!DF->getContents().empty())
-          return;
-    Text->setFlags(Text->getFlags() | ELF::SHF_AARCH64_PURECODE);
+    bool Empty = true;
+    for (auto &F : *Text) {
+      if (auto *DF = dyn_cast<MCDataFragment>(&F)) {
+        if (!DF->getContents().empty()) {
+          Empty = false;
+          break;
+        }
+      }
+    }
+    if (Empty)
+      Text->setFlags(Text->getFlags() | ELF::SHF_AARCH64_PURECODE);
   }
 
   MCSectionELF *MemtagSec = nullptr;
diff --git a/llvm/test/MC/AArch64/execute-only-memtag.ll b/llvm/test/MC/AArch64/execute-only-memtag.ll
new file mode 100644
index 0000000000000..02daf3179101f
--- /dev/null
+++ b/llvm/test/MC/AArch64/execute-only-memtag.ll
@@ -0,0 +1,18 @@
+; RUN: llc %s -mtriple=aarch64-linux-android31 -filetype=obj -o %t.o
+; RUN: llvm-readelf -r %t.o | FileCheck %s
+
+; CHECK:      Relocation section '.rela.memtag.globals.static' at offset {{.*}} contains 1 entries:
+; CHECK-NEXT:      Type      {{.*}} Symbol's Name
+; CHECK-NEXT: R_AARCH64_NONE {{.*}} global
+
+@global = global i32 1, sanitize_memtag
+
+define void @foo() {
+  ret void
+}
+
+define void @bar() #0 {
+  ret void
+}
+
+attributes #0 = { "target-features"="+execute-only" }

Comment on lines +514 to +522
bool Empty = true;
for (auto &F : *Text) {
if (auto *DF = dyn_cast<MCDataFragment>(&F)) {
if (!DF->getContents().empty()) {
Empty = false;
break;
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use something like all_of(*Text, [](***) {return DF->getContents().empty();} here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to do that too, but I get the following error:

error: no matching function for call to '__iterator_category'
note: candidate template ignored: substitution failure [with _Iter = llvm::MCSection::iterator]: no type named 'iterator_category' in 'std::iterator_traits<llvm::MCSection::iterator>'

To me it looks like MCSection::iterator is not a proper iterator according to the standard library, so we can't use std::all_of (which llvm::all_of uses).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Thanks for checking.

Comment on lines +514 to +522
bool Empty = true;
for (auto &F : *Text) {
if (auto *DF = dyn_cast<MCDataFragment>(&F)) {
if (!DF->getContents().empty()) {
Empty = false;
break;
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Thanks for checking.

@Il-Capitano Il-Capitano merged commit 5ff8c03 into llvm:main Apr 1, 2025
14 checks passed
@Il-Capitano Il-Capitano deleted the fix-execute-only-memtag branch April 7, 2025 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 llvm:mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants