[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:54:28 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: ABWI-Y
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/213539.diff
3 Files Affected:
- (added) clang/test/Parser/ms-inline-asm-div-by-zero.c (+5)
- (modified) llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp (+56-21)
- (added) llvm/test/MC/X86/intel-expr-div-by-zero.s (+7)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/213539
More information about the cfe-commits
mailing list