[clang] [llvm] [X86][AsmParser] Fix compiler crash on division by zero in MS inline asm (PR #213539)

via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 2 05:53:31 PDT 2026


https://github.com/ABWI-Y created https://github.com/llvm/llvm-project/pull/213539

This fixes issue #213415. If a user writes something like '1 / 0' or '1 % 0' in assembly, the compiler will now show a normal error message instead of crashing completely.

Fixes #213415

>From fd1143ef964254f84f1117d683a32f01318efcaf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=99=88=E7=BA=AA=E5=85=83?=
 <chenjiyuan at chenjiyuandeMacBook-Air.local>
Date: Sun, 2 Aug 2026 20:47:13 +0800
Subject: [PATCH] [X86][AsmParser] Fix compiler crash on division by zero in MS
 inline asm

This fixes issue #213415. If a user writes something like '1 / 0' or '1 % 0' in assembly, the compiler will now show a normal error message instead of crashing completely.

Fixes #213415
---
 clang/test/Parser/ms-inline-asm-div-by-zero.c |  5 ++
 .../lib/Target/X86/AsmParser/X86AsmParser.cpp | 77 ++++++++++++++-----
 llvm/test/MC/X86/intel-expr-div-by-zero.s     |  7 ++
 3 files changed, 68 insertions(+), 21 deletions(-)
 create mode 100644 clang/test/Parser/ms-inline-asm-div-by-zero.c
 create mode 100644 llvm/test/MC/X86/intel-expr-div-by-zero.s

diff --git a/clang/test/Parser/ms-inline-asm-div-by-zero.c b/clang/test/Parser/ms-inline-asm-div-by-zero.c
new file mode 100644
index 0000000000000..14de3b905735e
--- /dev/null
+++ b/clang/test/Parser/ms-inline-asm-div-by-zero.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fms-extensions -fasm-blocks -fsyntax-only -verify %s
+
+void foo() { // expected-note {{to match this '{'}}
+  __asm { return 1 / 0; } // expected-error {{division by zero in assembly expression}}
+} // expected-error {{expected '}'}}
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index 54edcba34a7e9..e0ce48d91bc54 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -268,7 +268,7 @@ class X86AsmParser : public MCTargetAsmParser {
       InfixOperatorStack.push_back(Op);
     }
 
-    int64_t execute() {
+    bool execute(int64_t &Result, StringRef &ErrMsg) {
       // Push any remaining operators onto the postfix stack.
       while (!InfixOperatorStack.empty()) {
         InfixCalculatorTok StackOp = InfixOperatorStack.pop_back_val();
@@ -276,8 +276,10 @@ class X86AsmParser : public MCTargetAsmParser {
           PostfixStack.push_back(std::make_pair(StackOp, 0));
       }
 
-      if (PostfixStack.empty())
-        return 0;
+      if (PostfixStack.empty()) {
+        Result = 0;
+        return false;
+      }
 
       SmallVector<ICToken, 16> OperandStack;
       for (const ICToken &Op : PostfixStack) {
@@ -325,13 +327,20 @@ class X86AsmParser : public MCTargetAsmParser {
           case IC_DIVIDE:
             assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
                     "Divide operation with an immediate and a register!");
-            assert (Op2.second != 0 && "Division by zero!");
+            if (Op2.second == 0) {
+              ErrMsg = "division by zero";
+              return true;
+            }
             Val = Op1.second / Op2.second;
             OperandStack.push_back(std::make_pair(IC_IMM, Val));
             break;
           case IC_MOD:
             assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
                     "Modulo operation with an immediate and a register!");
+            if (Op2.second == 0) {
+              ErrMsg = "division by zero";
+              return true;
+            }
             Val = Op1.second % Op2.second;
             OperandStack.push_back(std::make_pair(IC_IMM, Val));
             break;
@@ -407,7 +416,8 @@ class X86AsmParser : public MCTargetAsmParser {
         }
       }
       assert (OperandStack.size() == 1 && "Expected a single result.");
-      return OperandStack.pop_back_val().second;
+      Result = OperandStack.pop_back_val().second;
+      return false;
     }
   };
 
@@ -489,7 +499,13 @@ class X86AsmParser : public MCTargetAsmParser {
     unsigned getSize() const { return CurType.Size; }
     unsigned getElementSize() const { return CurType.ElementSize; }
     unsigned getLength() const { return CurType.Length; }
-    int64_t getImm() { return Imm + IC.execute(); }
+    bool getImm(int64_t &Result, StringRef &ErrMsg) {
+      int64_t ICResult;
+      if (IC.execute(ICResult, ErrMsg))
+        return true;
+      Result = Imm + ICResult;
+      return false;
+    }
     bool isValidEndState() const {
       return State == IES_RBRAC || State == IES_RPAREN ||
              State == IES_INTEGER || State == IES_REGISTER ||
@@ -890,6 +906,29 @@ class X86AsmParser : public MCTargetAsmParser {
       default:
         State = IES_ERROR;
         break;
+      case IES_DIVIDE:
+      case IES_MOD: {
+        auto HasError = [&ErrMsg](IntelExprState IES, int64_t TmpInt) {
+          if (TmpInt != 0)
+            return false;
+          switch (IES) {
+          case IES_DIVIDE:
+            ErrMsg = "division by zero in assembly expression";
+            break;
+          case IES_MOD:
+            ErrMsg = "modulo by zero in assembly expression";
+            break;
+          default:
+            llvm_unreachable("unreachable");
+          }
+          return true;
+        };
+        if (HasError(State, TmpInt)) {
+          State = IES_ERROR;
+          return true;
+        }
+        [[fallthrough]];
+      }
       case IES_PLUS:
       case IES_MINUS:
       case IES_NOT:
@@ -904,8 +943,6 @@ class X86AsmParser : public MCTargetAsmParser {
       case IES_GE:
       case IES_LSHIFT:
       case IES_RSHIFT:
-      case IES_DIVIDE:
-      case IES_MOD:
       case IES_MULTIPLY:
       case IES_LPAREN:
       case IES_INIT:
@@ -1189,8 +1226,8 @@ class X86AsmParser : public MCTargetAsmParser {
                                bool &ParseError, SMLoc &End);
   bool ParseMasmNamedOperator(StringRef Name, IntelExprStateMachine &SM,
                               bool &ParseError, SMLoc &End);
-  void RewriteIntelExpression(IntelExprStateMachine &SM, SMLoc Start,
-                              SMLoc End);
+  void RewriteIntelExpression(IntelExprStateMachine &SM, SMLoc Start, SMLoc End,
+                              int64_t Imm);
   bool ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End);
   bool ParseIntelInlineAsmIdentifier(const MCExpr *&Val, StringRef &Identifier,
                                      InlineAsmIdentifierInfo &Info,
@@ -2246,7 +2283,7 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
 }
 
 void X86AsmParser::RewriteIntelExpression(IntelExprStateMachine &SM,
-                                          SMLoc Start, SMLoc End) {
+                                          SMLoc Start, SMLoc End, int64_t Imm) {
   SMLoc Loc = Start;
   unsigned ExprLen = End.getPointer() - Start.getPointer();
   // Skip everything before a symbol displacement (if we have one)
@@ -2275,8 +2312,8 @@ void X86AsmParser::RewriteIntelExpression(IntelExprStateMachine &SM,
   if (SM.isOffsetOperator())
     OffsetNameStr = SM.getSymName();
   // Emit it
-  IntelExpr Expr(BaseRegStr, IndexRegStr, SM.getScale(), OffsetNameStr,
-                 SM.getImm(), SM.isMemExpr());
+  IntelExpr Expr(BaseRegStr, IndexRegStr, SM.getScale(), OffsetNameStr, Imm,
+                 SM.isMemExpr());
   InstInfo->AsmRewrites->emplace_back(Loc, ExprLen, Expr);
 }
 
@@ -2717,10 +2754,14 @@ bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) {
   if (ParseIntelExpression(SM, End))
     return true;
 
+  StringRef ErrMsg;
+  int64_t Imm;
+  if (SM.getImm(Imm, ErrMsg))
+    return Error(Start, ErrMsg);
+
   if (isParsingMSInlineAsm())
-    RewriteIntelExpression(SM, Start, Tok.getLoc());
+    RewriteIntelExpression(SM, Start, Tok.getLoc(), Imm);
 
-  int64_t Imm = SM.getImm();
   const MCExpr *Disp = SM.getSym();
   const MCExpr *ImmDisp = MCConstantExpr::create(Imm, getContext());
   if (Disp && Imm)
@@ -2747,7 +2788,6 @@ bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) {
     return false;
   }
 
-  StringRef ErrMsg;
   MCRegister BaseReg = SM.getBaseReg();
   MCRegister IndexReg = SM.getIndexReg();
   if (IndexReg && BaseReg == X86::RIP)
@@ -3647,11 +3687,6 @@ bool X86AsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
     Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc));
   }
 
-  // Parse condtional flags after mnemonic.
-  if ((Name.starts_with("ccmp") || Name.starts_with("ctest")) &&
-      parseCFlagsOp(Operands))
-    return true;
-
   // This does the actual operand parsing.  Don't parse any more if we have a
   // prefix juxtaposed with an operation like "lock incl 4(%rax)", because we
   // just want to parse the "lock" as the first instruction and the "incl" as
diff --git a/llvm/test/MC/X86/intel-expr-div-by-zero.s b/llvm/test/MC/X86/intel-expr-div-by-zero.s
new file mode 100644
index 0000000000000..7cf4ed04336c7
--- /dev/null
+++ b/llvm/test/MC/X86/intel-expr-div-by-zero.s
@@ -0,0 +1,7 @@
+# RUN: not llvm-mc -triple x86_64-unknown-unknown -x86-asm-syntax=intel %s 2>&1 | FileCheck %s
+
+# CHECK: error: division by zero
+mov eax, 1 / 0
+
+# CHECK: error: division by zero
+mov eax, 1 % 0



More information about the cfe-commits mailing list