[llvm] [IR] Fix crash on malformed '@' inline asm constraints (PR #224300)

Daniel Petrovic via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 01:33:59 PDT 2026


https://github.com/daniel-petrovic updated https://github.com/llvm/llvm-project/pull/224300

>From 5f565ea8ff91bae0a9fb18abe2c3cc5459b0a141 Mon Sep 17 00:00:00 2001
From: Daniel Petrovic <daniel-dev at hotmail.de>
Date: Thu, 17 Sep 2026 15:23:47 +0200
Subject: [PATCH] [IR] Fix crash on malformed '@' inline asm constraints

InlineAsm::ConstraintInfo::Parse trusted asserts (compiled out under
NDEBUG) for the '@' multi-letter constraint marker: a non-digit after
'@', a trailing '@', or a count exceeding the remaining characters all
caused an out-of-bounds StringRef read. A release-built llvm-as crashed
on "=@ccz"; verifyModule hit the same read via the C++ API. Replace the
asserts with bounds checks that return a parse error, and reject a
trailing '^' the same way.

Fixes: https://github.com/llvm/llvm-project/issues/223956
---
 llvm/lib/IR/InlineAsm.cpp                     | 13 ++++--
 .../Assembler/inline-asm-constraint-error.ll  | 43 +++++++++++++++++++
 2 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/IR/InlineAsm.cpp b/llvm/lib/IR/InlineAsm.cpp
index 922081468a7750..6b97384d65081b 100644
--- a/llvm/lib/IR/InlineAsm.cpp
+++ b/llvm/lib/IR/InlineAsm.cpp
@@ -197,17 +197,24 @@ bool InlineAsm::ConstraintInfo::Parse(StringRef Str,
       ++I;
     } else if (*I == '^') {
       // Multi-letter constraint
-      // FIXME: For now assuming these are 2-character constraints.
+      if (static_cast<int>(E - I) < 3)
+        return true; // "^" + 2 letters.
       pCodes->push_back(std::string(StringRef(I + 1, 2)));
       I += 3;
     } else if (*I == '@') {
       // Multi-letter constraint
       ++I;
+      if (I == E)
+        return true; // "@"
       unsigned char C = static_cast<unsigned char>(*I);
-      assert(isdigit(C) && "Expected a digit!");
+      if (!isdigit(C))
+        return true; // Expected a digit after '@'.
       int N = C - '0';
-      assert(N > 0 && "Found a zero letter constraint!");
+      if (N == 0)
+        return true; // Zero-length constraint not allowed.
       ++I;
+      if (static_cast<int>(E - I) < N)
+        return true; // Not enough characters.
       pCodes->push_back(std::string(StringRef(I, N)));
       I += N;
     } else {
diff --git a/llvm/test/Assembler/inline-asm-constraint-error.ll b/llvm/test/Assembler/inline-asm-constraint-error.ll
index f9d030c0434eb2..e39d337857b833 100644
--- a/llvm/test/Assembler/inline-asm-constraint-error.ll
+++ b/llvm/test/Assembler/inline-asm-constraint-error.ll
@@ -8,6 +8,11 @@
 ; RUN: not llvm-as < %t/incorrect-arg-num.ll 2>&1 | FileCheck %s --check-prefix=CHECK-INCORRECT-ARG-NUM
 ; RUN: not llvm-as < %t/label-after-clobber.ll 2>&1 | FileCheck %s --check-prefix=CHECK-LABEL-AFTER-CLOBBER
 ; RUN: not llvm-as < %t/output-after-label.ll 2>&1 | FileCheck %s --check-prefix=CHECK-OUTPUT-AFTER-LABEL
+; RUN: not llvm-as < %t/at-bad.ll 2>&1 | FileCheck %s --check-prefix=CHECK-AT-BAD
+; RUN: not llvm-as < %t/at-eof.ll 2>&1 | FileCheck %s --check-prefix=CHECK-AT-EOF
+; RUN: not llvm-as < %t/at-zero.ll 2>&1 | FileCheck %s --check-prefix=CHECK-AT-ZERO
+; RUN: not llvm-as < %t/at-short.ll 2>&1 | FileCheck %s --check-prefix=CHECK-AT-SHORT
+; RUN: not llvm-as < %t/caret-short.ll 2>&1 | FileCheck %s --check-prefix=CHECK-CARET-SHORT
 
 ;--- parse-fail.ll
 ; CHECK-PARSE-FAIL: failed to parse constraints
@@ -80,3 +85,41 @@ define void @foo() {
 2:
   ret void
 }
+
+;--- at-bad.ll
+; CHECK-AT-BAD: failed to parse constraints
+define void @foo() {
+  ; '@' must be followed by a digit giving the number of constraint letters.
+  call void asm sideeffect "", "=@ccz"()
+  ret void
+}
+
+;--- at-eof.ll
+; CHECK-AT-EOF: failed to parse constraints
+define void @foo() {
+  call void asm sideeffect "", "=@"()
+  ret void
+}
+
+;--- at-zero.ll
+; CHECK-AT-ZERO: failed to parse constraints
+define void @foo() {
+  call void asm sideeffect "", "=@0abc"()
+  ret void
+}
+
+;--- at-short.ll
+; CHECK-AT-SHORT: failed to parse constraints
+define void @foo() {
+  ; Not enough letters for the declared count.
+  call void asm sideeffect "", "=@3ab"()
+  ret void
+}
+
+;--- caret-short.ll
+; CHECK-CARET-SHORT: failed to parse constraints
+define void @foo() {
+  ; '^' must be followed by exactly two constraint letters.
+  call void asm sideeffect "", "=^x"()
+  ret void
+}



More information about the llvm-commits mailing list