[llvm] [WebAssembly] Don't assert on a non-zero call_indirect table index (PR #210120)
Jonas Devlieghere via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 10:46:57 PDT 2026
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/210120
WebAssemblyInstPrinter::printInst asserted that a non-symbol table operand of call_indirect is the immediate 0, on the assumption that only MVP single-table compilation units reach the printer. That is true for code generated by the compiler, but the printer is shared by the disassembler.
The disassembler must produce output for any byte sequence it is pointed at and shouldn't abort on the operand values it decodes. A non-zero immediate table index is both a valid encoding, from a multi-table module, and a routine result of best-effort disassembly of a range that is not all code, which is how I hit this in LLDB.
Print the table operand when it is a symbol or a non-zero immediate, and omit it only for the implicit table 0. This makes the output lossless and unambiguous, matching how a table symbol is already printed. MVP and table-symbol output are unchanged, so there is no effect on the compiler's assembly.
>From 989a030bc0fff8f950f69b0276438eb029833b9a Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 16 Jul 2026 10:32:56 -0700
Subject: [PATCH] [WebAssembly] Don't assert on a non-zero call_indirect table
index
WebAssemblyInstPrinter::printInst asserted that a non-symbol table
operand of call_indirect is the immediate 0, on the assumption that
only MVP single-table compilation units reach the printer. That is
true for code generated by the compiler, but the printer is shared by
the disassembler.
The disassembler must produce output for any byte sequence it is pointed
at and shouldn't abort on the operand values it decodes. A non-zero
immediate table index is both a valid encoding, from a multi-table
module, and a routine result of best-effort disassembly of a range
that is not all code, which is how I hit this in LLDB.
Print the table operand when it is a symbol or a non-zero immediate,
and omit it only for the implicit table 0. This makes the output
lossless and unambiguous, matching how a table symbol is already
printed. MVP and table-symbol output are unchanged, so there is no
effect on the compiler's assembly.
---
.../MCTargetDesc/WebAssemblyInstPrinter.cpp | 17 +++++++++--------
llvm/test/MC/Disassembler/WebAssembly/wasm.txt | 5 +++++
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 8cee0788def0a..5bfaffba3e578 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -60,19 +60,20 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
case WebAssembly::RET_CALL_INDIRECT:
case WebAssembly::CALL_INDIRECT_S:
case WebAssembly::RET_CALL_INDIRECT_S: {
- // A special case for call_indirect (and ret_call_indirect), if the table
- // operand is a symbol: the order of the type and table operands is inverted
- // in the text format relative to the binary format. Otherwise if table the
- // operand isn't a symbol, then we have an MVP compilation unit, and the
- // table shouldn't appear in the output.
+ // A special case for call_indirect (and ret_call_indirect): the order of
+ // the type and table operands is inverted in the text format relative to
+ // the binary format. The table operand is omitted when it refers to the
+ // default table 0 of an MVP compilation unit. Otherwise (a table symbol,
+ // or a non-zero table index from a multi-table module) it is printed
+ // first. A disassembler can also hand us an arbitrary immediate here when
+ // decoding misaligned bytes, so print it rather than asserting.
OS << "\t";
OS << getMnemonic(*MI).first;
OS << " ";
- if (MI->getOperand(TableOperand).isExpr()) {
+ const MCOperand &TableOp = MI->getOperand(TableOperand);
+ if (TableOp.isExpr() || (TableOp.isImm() && TableOp.getImm() != 0)) {
printOperand(MI, TableOperand, STI, OS);
OS << ", ";
- } else {
- assert(MI->getOperand(TableOperand).getImm() == 0);
}
printOperand(MI, TypeOperand, STI, OS);
if (MI->getOpcode() == WebAssembly::CALL_INDIRECT)
diff --git a/llvm/test/MC/Disassembler/WebAssembly/wasm.txt b/llvm/test/MC/Disassembler/WebAssembly/wasm.txt
index 3a418ea32c12a..e0f8598db71e6 100644
--- a/llvm/test/MC/Disassembler/WebAssembly/wasm.txt
+++ b/llvm/test/MC/Disassembler/WebAssembly/wasm.txt
@@ -20,6 +20,11 @@
# FIXME: WebAssemblyInstPrinter does not print immediates.
0x11 0x80 0x01 0x00
+# A non-zero table index (a multi-table module, or misaligned bytes fed to the
+# disassembler) must be printed rather than trigger an assertion.
+# CHECK: call_indirect 1, 0
+0x11 0x00 0x01
+
# CHECK: call 0
0x10 0x00
More information about the llvm-commits
mailing list