[llvm] [CodeGen] Assert on invalid patchable-function-entry/prefix attributes (PR #194726)

via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 28 14:01:31 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-powerpc

Author: JP Hafer (jph-13)

<details>
<summary>Changes</summary>

Replace unchecked getAsInteger() calls for the "patchable-function-entry" and "patchable-function-prefix" function attributes with assertions across AsmPrinter and all backend targets.

The IR Verifier already validates these attributes as unsigned base-10 integers via checkUnsignedBaseTenFuncAttr, so a parse failure at the point of use indicates a verifier bypass or IR corruption. The RISC-V backend already follows this pattern (RISCVAsmPrinter.cpp); this brings the remaining backends in line.

Affected targets: AArch64, ARM, LoongArch, PowerPC, RISC-V, SystemZ, X86.

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


12 Files Affected:

- (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+28-12) 
- (modified) llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp (+10-5) 
- (modified) llvm/lib/Target/ARM/ARMAsmPrinter.cpp (+10-5) 
- (modified) llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp (+4-3) 
- (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp (+4-3) 
- (modified) llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (+15-7) 
- (modified) llvm/lib/Target/PowerPC/PPCInstrInfo.cpp (+7-3) 
- (modified) llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp (+10-5) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.cpp (+4-4) 
- (modified) llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp (+4-3) 
- (modified) llvm/lib/Target/X86/X86AsmPrinter.cpp (+8-4) 
- (modified) llvm/lib/Target/X86/X86MCInstLower.cpp (+12-7) 


``````````diff
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 8c75ca7c17f7e..766dbed8f8e7a 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1085,12 +1085,20 @@ void AsmPrinter::emitFunctionHeader() {
   // place prefix data before NOPs.
   unsigned PatchableFunctionPrefix = 0;
   unsigned PatchableFunctionEntry = 0;
-  (void)F.getFnAttribute("patchable-function-prefix")
-      .getValueAsString()
-      .getAsInteger(10, PatchableFunctionPrefix);
-  (void)F.getFnAttribute("patchable-function-entry")
-      .getValueAsString()
-      .getAsInteger(10, PatchableFunctionEntry);
+  if (F.hasFnAttribute("patchable-function-prefix")) {
+    [[maybe_unused]] bool Result =
+        F.getFnAttribute("patchable-function-prefix")
+            .getValueAsString()
+            .getAsInteger(10, PatchableFunctionPrefix);
+    assert(!Result && "Enforced by the verifier");
+  }
+  if (F.hasFnAttribute("patchable-function-entry")) {
+    [[maybe_unused]] bool Result =
+        F.getFnAttribute("patchable-function-entry")
+            .getValueAsString()
+            .getAsInteger(10, PatchableFunctionEntry);
+    assert(!Result && "Enforced by the verifier");
+  }
   if (PatchableFunctionPrefix) {
     CurrentPatchableFunctionEntrySym =
         OutContext.createLinkerPrivateTempSymbol();
@@ -5102,12 +5110,20 @@ void AsmPrinter::recordSled(MCSymbol *Sled, const MachineInstr &MI,
 void AsmPrinter::emitPatchableFunctionEntries() {
   const Function &F = MF->getFunction();
   unsigned PatchableFunctionPrefix = 0, PatchableFunctionEntry = 0;
-  (void)F.getFnAttribute("patchable-function-prefix")
-      .getValueAsString()
-      .getAsInteger(10, PatchableFunctionPrefix);
-  (void)F.getFnAttribute("patchable-function-entry")
-      .getValueAsString()
-      .getAsInteger(10, PatchableFunctionEntry);
+  if (F.hasFnAttribute("patchable-function-prefix")) {
+    [[maybe_unused]] bool Result =
+        F.getFnAttribute("patchable-function-prefix")
+            .getValueAsString()
+            .getAsInteger(10, PatchableFunctionPrefix);
+    assert(!Result && "Enforced by the verifier");
+  }
+  if (F.hasFnAttribute("patchable-function-entry")) {
+    [[maybe_unused]] bool Result =
+        F.getFnAttribute("patchable-function-entry")
+            .getValueAsString()
+            .getAsInteger(10, PatchableFunctionEntry);
+    assert(!Result && "Enforced by the verifier");
+  }
   if (!PatchableFunctionPrefix && !PatchableFunctionEntry)
     return;
   const unsigned PointerSize = getPointerSize();
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 97edd896c5992..c4d2ec6ca250a 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -688,11 +688,16 @@ void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
     // Adjust the offset for patchable-function-prefix. This assumes that
     // patchable-function-prefix is the same for all functions.
     int64_t PrefixNops = 0;
-    (void)MI.getMF()
-        ->getFunction()
-        .getFnAttribute("patchable-function-prefix")
-        .getValueAsString()
-        .getAsInteger(10, PrefixNops);
+    if (MI.getMF()->getFunction().hasFnAttribute(
+            "patchable-function-prefix")) {
+      [[maybe_unused]] bool Result =
+          MI.getMF()
+              ->getFunction()
+              .getFnAttribute("patchable-function-prefix")
+              .getValueAsString()
+              .getAsInteger(10, PrefixNops);
+      assert(!Result && "Enforced by the verifier");
+    }
 
     // Load the target function type hash.
     EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi)
diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
index fb2bbb5680156..5844d8cceadce 100644
--- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -1916,11 +1916,16 @@ void ARMAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
 
   // Adjust the offset for patchable-function-prefix.
   int64_t PrefixNops = 0;
-  MI.getMF()
-      ->getFunction()
-      .getFnAttribute("patchable-function-prefix")
-      .getValueAsString()
-      .getAsInteger(10, PrefixNops);
+  if (MI.getMF()->getFunction().hasFnAttribute(
+          "patchable-function-prefix")) {
+    [[maybe_unused]] bool Result =
+        MI.getMF()
+            ->getFunction()
+            .getFnAttribute("patchable-function-prefix")
+            .getValueAsString()
+            .getAsInteger(10, PrefixNops);
+    assert(!Result && "Enforced by the verifier");
+  }
 
   // Emit the appropriate instruction sequence based on the opcode variant.
   switch (MI.getOpcode()) {
diff --git a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
index 4b5cba716c638..19d2a6e259ade 100644
--- a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp
@@ -216,10 +216,11 @@ void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
   const Function &F = MF->getFunction();
   if (F.hasFnAttribute("patchable-function-entry")) {
     unsigned Num;
-    if (F.getFnAttribute("patchable-function-entry")
+    [[maybe_unused]] bool Result =
+        F.getFnAttribute("patchable-function-entry")
             .getValueAsString()
-            .getAsInteger(10, Num))
-      return;
+            .getAsInteger(10, Num);
+    assert(!Result && "Enforced by the verifier");
     emitNops(Num);
     return;
   }
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
index 631565b963b79..3ad81c5285848 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
@@ -268,10 +268,11 @@ unsigned LoongArchInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     const Function &F = MF->getFunction();
     if (F.hasFnAttribute("patchable-function-entry")) {
       unsigned Num;
-      if (F.getFnAttribute("patchable-function-entry")
+      [[maybe_unused]] bool Result =
+          F.getFnAttribute("patchable-function-entry")
               .getValueAsString()
-              .getAsInteger(10, Num))
-        return 0;
+              .getAsInteger(10, Num);
+      assert(!Result && "Enforced by the verifier");
       return Num * 4;
     }
     [[fallthrough]];
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 49c54fbae1bf0..c2731fa158345 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -952,10 +952,14 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
     assert(!Subtarget->isAIXABI() &&
            "AIX does not support patchable function entry!");
     const Function &F = MF->getFunction();
-    unsigned Num = 0;
-    (void)F.getFnAttribute("patchable-function-entry")
-        .getValueAsString()
-        .getAsInteger(10, Num);
+    if (!F.hasFnAttribute("patchable-function-entry"))
+      return;
+    unsigned Num;
+    [[maybe_unused]] bool Result =
+        F.getFnAttribute("patchable-function-entry")
+            .getValueAsString()
+            .getAsInteger(10, Num);
+    assert(!Result && "Enforced by the verifier");
     if (!Num)
       return;
     emitNops(Num);
@@ -1818,9 +1822,13 @@ void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) {
     // XRAY is only supported on PPC Linux little endian.
     const Function &F = MF->getFunction();
     unsigned Num = 0;
-    (void)F.getFnAttribute("patchable-function-entry")
-        .getValueAsString()
-        .getAsInteger(10, Num);
+    if (F.hasFnAttribute("patchable-function-entry")) {
+      [[maybe_unused]] bool Result =
+          F.getFnAttribute("patchable-function-entry")
+              .getValueAsString()
+              .getAsInteger(10, Num);
+      assert(!Result && "Enforced by the verifier");
+    }
 
     if (!MAI->isLittleEndian() || Num)
       break;
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index f854dca003964..c3c96859225c9 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -3024,9 +3024,13 @@ unsigned PPCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     const MachineFunction *MF = MI.getParent()->getParent();
     const Function &F = MF->getFunction();
     unsigned Num = 0;
-    (void)F.getFnAttribute("patchable-function-entry")
-        .getValueAsString()
-        .getAsInteger(10, Num);
+    if (F.hasFnAttribute("patchable-function-entry")) {
+      [[maybe_unused]] bool Result =
+          F.getFnAttribute("patchable-function-entry")
+              .getValueAsString()
+              .getAsInteger(10, Num);
+      assert(!Result && "Enforced by the verifier");
+    }
     if (Num || MF->getTarget().getTargetTriple().isOSAIX() ||
         !MF->getTarget().getTargetTriple().isLittleEndian())
       return Num * 4;
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index d71fd640be7bc..0baa2f7d1c2a8 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -682,11 +682,16 @@ void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
     // patchable-function-prefix is the same for all functions.
     int NopSize = STI->hasStdExtZca() ? 2 : 4;
     int64_t PrefixNops = 0;
-    (void)MI.getMF()
-        ->getFunction()
-        .getFnAttribute("patchable-function-prefix")
-        .getValueAsString()
-        .getAsInteger(10, PrefixNops);
+    if (MI.getMF()->getFunction().hasFnAttribute(
+            "patchable-function-prefix")) {
+      [[maybe_unused]] bool Result =
+          MI.getMF()
+              ->getFunction()
+              .getFnAttribute("patchable-function-prefix")
+              .getValueAsString()
+              .getAsInteger(10, PrefixNops);
+      assert(!Result && "Enforced by the verifier");
+    }
 
     // Load the target function type hash.
     EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::LW)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 6671669a8942b..0d4375906b0ff 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -2087,11 +2087,11 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     if (Opcode == TargetOpcode::PATCHABLE_FUNCTION_ENTER &&
         F.hasFnAttribute("patchable-function-entry")) {
       unsigned Num;
-      if (F.getFnAttribute("patchable-function-entry")
+      [[maybe_unused]] bool Result =
+          F.getFnAttribute("patchable-function-entry")
               .getValueAsString()
-              .getAsInteger(10, Num))
-        return get(Opcode).getSize();
-
+              .getAsInteger(10, Num);
+      assert(!Result && "Enforced by the verifier");
       // Number of C.NOP or NOP
       return (STI.hasStdExtZca() ? 2 : 4) * Num;
     }
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 7871e4a53de2a..ed745d5c79aa0 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -941,10 +941,11 @@ void SystemZAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
     unsigned Num;
     // get M-N from function attribute (CodeGenFunction subtracts N
     // from M to yield the correct patchable-function-entry).
-    if (F.getFnAttribute("patchable-function-entry")
+    [[maybe_unused]] bool Result =
+        F.getFnAttribute("patchable-function-entry")
             .getValueAsString()
-            .getAsInteger(10, Num))
-      return;
+            .getAsInteger(10, Num);
+    assert(!Result && "Enforced by the verifier");
     // Emit M-N 2-byte nops. Use getNop() here instead of emitNops()
     // to keep it aligned with the common code implementation emitting
     // the prefix nops.
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 94dd706fe9944..367c87d399289 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -154,10 +154,14 @@ void X86AsmPrinter::EmitKCFITypePadding(const MachineFunction &MF,
   // Keep the function entry aligned, taking patchable-function-prefix into
   // account if set.
   int64_t PrefixBytes = 0;
-  (void)MF.getFunction()
-      .getFnAttribute("patchable-function-prefix")
-      .getValueAsString()
-      .getAsInteger(10, PrefixBytes);
+  if (MF.getFunction().hasFnAttribute("patchable-function-prefix")) {
+    [[maybe_unused]] bool Result =
+        MF.getFunction()
+            .getFnAttribute("patchable-function-prefix")
+            .getValueAsString()
+            .getAsInteger(10, PrefixBytes);
+    assert(!Result && "Enforced by the verifier");
+  }
 
   // Also take the type identifier into account if we're emitting
   // one. Otherwise, just pad with nops. The X86::MOV32ri instruction emitted
diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp
index 98126ec07b74d..e1c22a9470d6f 100644
--- a/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -910,10 +910,14 @@ void X86AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
   // functions.
   const MachineFunction &MF = *MI.getMF();
   int64_t PrefixNops = 0;
-  (void)MF.getFunction()
-      .getFnAttribute("patchable-function-prefix")
-      .getValueAsString()
-      .getAsInteger(10, PrefixNops);
+  if (MF.getFunction().hasFnAttribute("patchable-function-prefix")) {
+    [[maybe_unused]] bool Result =
+        MF.getFunction()
+            .getFnAttribute("patchable-function-prefix")
+            .getValueAsString()
+            .getAsInteger(10, PrefixNops);
+    assert(!Result && "Enforced by the verifier");
+  }
 
   // KCFI allows indirect calls to any location that's preceded by a valid
   // type identifier. To avoid encoding the full constant into an instruction,
@@ -1311,10 +1315,11 @@ void X86AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
   const Function &F = MF->getFunction();
   if (F.hasFnAttribute("patchable-function-entry")) {
     unsigned Num;
-    if (F.getFnAttribute("patchable-function-entry")
+    [[maybe_unused]] bool Result =
+        F.getFnAttribute("patchable-function-entry")
             .getValueAsString()
-            .getAsInteger(10, Num))
-      return;
+            .getAsInteger(10, Num);
+    assert(!Result && "Enforced by the verifier");
     emitX86Nops(*OutStreamer, Num, Subtarget);
     return;
   }

``````````

</details>


https://github.com/llvm/llvm-project/pull/194726


More information about the llvm-commits mailing list